ORM中的Model与DDD中的DomainModel

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于ORM中的Model与DDD中的DomainModel的主要内容,如果未能解决你的问题,请参考以下文章

Django - 模型(model)-- ORM

Django学习---Models(ORM框架)

Django的orm中get和filter的不同

Django04-模型系统model

Django中的ORM

04-Django-基础篇-模型