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