2010-02-10 72 views
12

我有以下DB模型:DDD:枚舉等實體

**Person table** 
ID | Name | StateId 
------------------------------ 
1   Joe  1 
2   Peter  1 
3   John  2 

**State table** 
ID | Desc 
------------------------------ 
1   Working 
2   Vacation 

和域模型將被(簡化):

public class Person 
{ 
    public int Id { get; } 
    public string Name { get; set; } 
    public State State { get; set; } 
} 

public class State 
{ 
    private int id; 
    public string Name { get; set; } 
} 

的狀態可能會在域邏輯例如可以使用:

if(person.State == State.Working) 
    // some logic 

因此,從我的理解,國家就像一個價值對象,用於域邏輯檢查。但是它也需要存在於數據庫模型中才能表現清晰的ERM。使用這種方法的國家的名字將被硬編碼到域

public class State 
{ 
    private int id; 
    public string Name { get; set; } 

    public static State New {get {return new State([hardCodedIdHere?], [hardCodeNameHere?]);}} 
} 

但是:

所以狀態可能會擴展到。

你知道我的意思嗎?對於這樣的事情有沒有標準的方法?從我的角度來看,我想要做的是將一個對象(從ERM設計角度來看是持久的)用作我的域中的一種價值對象。你怎麼看?

問題更新: 也許我的問題還不夠清楚。

我需要知道的是,我將如何使用存儲在我的域邏輯中的數據庫中的實體(如狀態示例)。爲了避免這樣的事情:

if(person.State.Id == State.Working.Id) 
     // some logic 

if(person.State.Id == WORKING_ID) 
// some logic 
+0

由於您的國家在數據庫中有一個ID,所以它們是實體(值對象由其屬性標識,而不是ID)。也許你應該刪除它們並將值直接存儲在相應的數據庫表中? – ZeissS 2010-02-11 14:46:18

回答

7

A previous question of mine出土了一些有用的鏈接,我懷疑這些鏈接與你的問題有關,特別是Jimmy Bogard對Enumeration Classes的討論。

+0

現在使用他的枚舉類一段時間...偶然發現升級版本。 https://github.com/HeadspringLabs/Enumeration – CSharper 2015-05-20 19:45:20

+0

也可作爲NuGet包使用! - 不錯... http://www.nuget.org/packages/Enumeration – rohancragg 2015-06-02 14:20:12

3

這是一個常見的做法包括在枚舉值0的「未知」元素。如果你真的想要,你可以做到這一點並將其用於New狀態。

但是你所描述的是業務邏輯......在創建新對象之後設置狀態應該發生在業務邏輯層中,而不是在類本身內部。

0

在我的觀點中,領域層必須與DB模型/ ERM設計分離。我很難理解你對國家課的最終建議。恕我直言,這對於建立一種共同語言並不是一件好事,而這種語言是DDD的主要目的之一。

我會去一個更簡單的設計。該狀態屬於Person類。我會把它加入課堂。

public class Person 
{ 
    public int Id { get; } 
    public string Name { get; set; } 
    public PersonState State { get; set; } 
} 

國家本身似乎已經定義的值(我假設一個人在你的背景下僱員)不經常改變。所以我會將它建模爲枚舉並將其視爲數據類型。

enum Days {Working, Vacation}; 

在我看來,這是一個簡單易懂的設計。映射到ERM設計屬於持久層的恕我直言。那裏的枚舉必須映射到狀態表的鍵。這可以通過使用一個方面來保持原始域模型的清潔。

7

你提出的結構看起來很好。(術語題外話:因爲State有一個ID,它不是一個值對象,而是一個實體

枚舉是一個代碼味道,所以不要試圖走這條路。使用State模式更加面向對象地將行爲移動到狀態對象中。

不必編寫

if (person.State == State.Working) 
    // do something... 

在你的代碼,這將允許你寫

person.State.DoSomething(); 

這是更清潔,而且將允許您如果需要的話加入新的國家。

+0

爲什麼匿名downvote? – 2010-02-10 14:59:27

+0

問題與如何推動狀態模式有關,其給定的提問者正在使用狀態模式。 – 2010-02-11 17:24:51

+2

@Brian Leahy:我沒有看到問題中任何地方提到的State * pattern * – 2010-02-11 17:53:44

2

您希望創建一個工廠方法,根據存儲的值來實例化所需的相應狀態類。

public static State GetStateByID(StateEnum value) 
{ 
    if(value.Invalid) 
     throw new Exception(); 

switch(value) 
    case State.Working 
     return new WorkingState(); 
    case State.somethingelse 
     return new somethingelseState(); 
    case State.something 
     return new somethingState(); 
    case State.whatever 
     return new whateverState(); 

} 

當使用枚舉總是試圖使用0作爲無效。在引擎蓋下,枚舉是一個值類型,而未分配的int始終爲0.

通常將工廠(如this)與狀態模式結合使用。

所以,當你從數據庫中讀取存儲的整數值時,你可以將int轉換爲enum並用它調用工廠以獲取適當的State對象。

1

我個人認爲用ID編程是錯誤的。相反,我會修改你的表到以下幾點:

**State table** 
ID | Desc    | IsWorking | IsVacation 
----------------------------------------------------------- 
1   Working    True   False 
2   Vacation    False  True 

然後,我會使用這些屬性就如商業決策:

public void MakeDecisionOnState(State state) 
    { 
     if (state.IsVacation) 
      DoSomething(); 
     if (state.IsWorking) 
      DoSomethingElse(); 
    } 

或者通過更聰明,使用工廠模式根據這些屬性來創建正確的實例:

public abstract class State 
    { 
     public Guid Id { get; set; } 

     public string Description { get; set; } 

     public abstract void DoSomething(); 

    } 

    public class WorkingState : State 
    { 
     public override void DoSomething() 
     { 
      //Do something specific for the working state 
     } 
    } 

    public class VacationState : State 
    { 
     public override void DoSomething() 
     { 
      //Do something specific for the vacation state 
     } 
    } 

    public class StateFactory 
    { 
     public static State CreateState(IDataRecord record) 
     { 
      if (record.GetBoolean(2)) 
       return new WorkingState { Id = record.GetGuid(0), Description = record.GetString(1) }; 
      if (record.GetBoolean(3)) 
       return new VacationState { Id = record.GetGuid(0), Description = record.GetString(1) }; 

      throw new Exception("Data is screwed"); 
     } 
    } 

現在你已經消除了,如果/ switch語句,你的代碼可能僅僅是:

state.DoSomething(); 

我之所以這樣做是往往這些類型的實體(或DDD更可能值對象)可以由客戶進行配置,即它們可能不希望有一些國家的活躍在系統,或者他們可能希望將他們稱爲別的東西。通過對屬性進行編程,客戶可以隨意刪除/編輯記錄,即使該過程生成新的ID也不會影響系統,只需設置屬性即可。