ORM中的Model與DDD中的DomainModel


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:旅館聚合與房間聚合

在旅館信息系統管理里面,對旅館的操作會有獨立的模塊,參考聚合的設計原則

  1. 如果領域內的一個對象,我們會在后台有一個獨立的模塊去管理它,那它基本上也是聚合根了;

所以我們建立旅館聚合,代碼如下:

    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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM