0.引言
在現有的系統開發中,大部分的系統應該都會用到ORM,無論用的是EF還是NHibernate。作為對象和持久化數據的橋梁,ORM確實非常方便,以至於在DDD的時候,我們很自然的將 ORM中的Model(實體)表達成DDD中的 DomainModel(領域對象)。
但這真的合理嗎?我們先引入兩個例子來探討這個問題。
1.例子1:訂單聚合
我們看以上的聚合設計非常經典。Order對象作為聚合根,OrderItem建模成實體,只要在當前的訂單聚合中不重復即可。
但在真正的數據存儲的時候,我們的OrderItem對象肯定不能是這樣子的。
假如:我們有兩個訂單A和B,訂單A包含了商品1和商品2,訂單2包含商品2和商品3。
那么很明顯我們如果以OrderItem這個實體去存儲,必然會造成主鍵重復。在實際存儲的時候我們肯定也會為OrderItem增加其他的字段用來存儲他自己的主鍵信息。
比如我們給他建立一個獨立的ID:
public class OrderItem { /// <summary> /// 訂單項ID /// </summary> public string Id { get; set; } public string ProductId { get; set; } public string ProductName { get; set; } public float Price { get; set; } public int Count { get; set; } }
或則采用聯合主鍵:
public class OrderItem { /// <summary> /// 訂單ID /// </summary> public string OrderId { get; set; } public string ProductId { get; set; } public string ProductName { get; set; } public float Price { get; set; } public int Count { get; set; } }
2.例子2:旅館聚合與房間聚合
在旅館信息系統管理里面,對旅館的操作會有獨立的模塊,參考聚合的設計原則
- 如果領域內的一個對象,我們會在后台有一個獨立的模塊去管理它,那它基本上也是聚合根了;
所以我們建立旅館聚合,代碼如下:
public class Hotel { /// <summary> /// 聚合跟id /// </summary> public string Id { get; set; } /// <summary> /// 值對象 /// </summary> public string Name { get; set; } /// <summary> /// 房間列表 此處簡單標示 /// </summary> public IList<string> Rooms { get; set; } //其他信息略 //... }
對於旅館房間的也一樣我們會有單獨的模塊去管理,而且房間有單獨的狀態標示(房間是否有人入住,是否空房等等)
房間聚合如下:
public class Room { /// <summary> /// 房間id /// </summary> public string Id { get; set; } public string Name { get; set; } public string RoomType { get; set; } // 空 已預訂,已入住,臟房間等狀態 public RoomStatus Status { get; set; } /// <summary> /// 旅館聚合根ID /// </summary> public string HotelId { get; set; } }
如果是在ORM中上述很可能表達成如下實體:
public class Hotel { public string Id { get; set; } public string Name { get; set; } /// <summary> /// 房間列表 /// </summary> public virtual IList<Room> Rooms { get; set; } //其他信息略 //... }
和房間實體
public class Room { /// <summary> /// 房間id /// </summary> public string Id { get; set; } public string Name { get; set; } public string RoomType { get; set; } // 空 已預訂,已入住,臟房間等狀態 public RoomStatus Status { get; set; } /// <summary> /// 旅館 /// </summary> public virtual Hotel Hotel { get; set; } }
很明顯的可以看出,上述模型不是DDD中的領域對象模型。
3.結論:ORM中的Model不應該與DDD中的DomainModel等價
更多的:我們在設計數據庫表的時候,為了查詢性能考慮,會冗余一些信息等等。
通過以上的分析,我們可以得出結論:ORM中的Model不應該與DDD中的DomainModel等價。
我藉著本文來拋磚引玉。
國外的大牛寫的:Just-Stop-It!-The-Domain-Model-Is-Not-The-Persistence-Model.aspx