这是我第一次参加DDD。在公司,我们没有"域名大师"。我只读过DDD我需要用DDD aproach实现域名。
所以,我知道在域中没有数据库功能的地方。但是,如果我将我的域与Entity Framework和NOSQL数据库一起使用。使用EF我需要将集合虚拟化并在构造函数中分配为新的集合。这在DDD中是不好的?
我的代码:
public abstract class Merchant : AggregateRoot
{
public Company Company { get; set; } // Entity
public string CIF { get; set; }
public string NIP { get; set; }
public string Status { get; set; }
public Address Address { get; set; } // Entity
public Group Group { get; set; } // Entity
public virtual ICollection<Brand> Brands { get; set; } // Brand is entity
protected Merchant()
{
this.Brands = new List<Brand>();
}
}
答案 0 :(得分:4)
DDD空间中有关于该问题的multiple shades of opinion。
对我来说,“持久性无知”的主要衡量标准是:
我的数据库中的更改是否会破坏我的域层中的内容,强制执行 我打开域模型并修改东西来修复它?
如果我们看一下你的例子,答案显然是否定的。
如果您的实体类中的数据注释引用了表名或列名,或者您依赖于按惯例进行映射并更改了Merchant
,那么 就是数据库中的表名为Reseller
。但是,拥有默认构造函数和虚拟属性不会使您的域类在数据库更改时更加脆弱。
然后你有一个次要问题,一个不太重要的问题IMO:
ORM是否是我实现域实体的障碍 想要和他们需要的DDD兼容吗?
这个有点挑战。可能是,如果ORM强制您添加可能使域对象处于不一致状态的操作。我不会认为无参数构造函数倾向于那样,因为它可以是私有的,因此不可能用脚射击自己。与制定者相同。
有些人认为,诸如虚拟和无参数构造函数之类的小痕迹违反了DDD,因为你的实体不再是纯粹的,它们包含由ORM的存在引起的奇怪现象。因此,您应该创建第二个“持久性”模型,以使域模型不受污染。我不。我认为大多数时候在复杂性方面不值得权衡 - 只要持久性无知的第一条规则成立,你就可以忍受小怪癖。
答案 1 :(得分:1)
我会更关心公共setter而不是受保护的默认构造函数或虚拟属性。问题是可能导致实体的状态不一致。例如,您可能需要验证地址属性以确保设置了所有必需的属性,并且邮政编码对应于州/国家/地区。另一个例子是状态转换;一旦实体达到“最终”状态,就不能再改变了。
虽然您可以为实体创建单独的验证器并在持久化实体之前使用它们,但它会破坏富域模型的目的。
有几种方法可以解决这个问题。您可以创建镜像数据库模式的DTO对象,并使用加油器从这些DTO填充实体(带有受保护/内部属性设置器),假设数据库中的数据始终处于一致状态。所有新的更改都必须通过实体方法进行验证。然后你会根据最新的实体数据来水化DTO并坚持下去。
带事件源的CQRS是一种更高级的替代方案,它将所有更改保留为不可变日志/事件存储,而不是(仅)最新数据快照。但这不是每个域场景所必需的。