由于所有实体都有创建/修改记录的标记,我们可以将 Person 实体视为所有实体的聚合根吗?
也就是说,所有引用 Person 的实体都将成为 Person 的集合,例如
public class Person
{
public virtual int PersonId { get; set; }
public virtual string Lastname { get; set; }
public virtual IList<OrderHeader> CreatedOrders { get; set; }
public virtual IList<OrderHeader> ModifiedOrders { get; set; }
// Other entities that have a reference on Person will be mapped as a collection under
// the Person entity
}
public class OrderHeader
{
public virtual int OrderId { get; set; }
public virtual DateTime OrderDate { get; set; }
public virtual Customer Customer { get; set; }
public virtual string CommentsOnThisOrder { get; set; }
// stamp audit-level concerns
public virtual Person CreatedBy { get; set; }
public virtual DateTime DateCreated { get; set; }
public virtual Person ModifiedBy { get; set; }
public virtual DateTime DateModified { get; set; }
public virtual IList<OrderItem> OrderItems { get; set; }
}
public class OrderItem
{
public virtual OrderHeader OrderHeader { get; set; }
public virtual Product Product { get; set; }
public virtual int Quantity { get; set; }
public virtual decimal Price { get; set; }
}
这基本上会使所有实体成为 Person 的集合,这违反了 DDD 聚合根规则。
在我对 DDD 聚合的有限理解中,OrderHeader 不能成为 Person 的集合,因为我们不应该通过 Person 保存 Order 聚合。保存 Order 聚合(对象图)的唯一*entry*点必须从 OrderHeader 完成,而不是从 Person 完成。
现在我的真正目标来了,即使它看起来很脏,我仍然希望 Order 成为 Person 的集合:
如果 OrderHeader 未作为集合映射到 Person,则有一个 ORM *cough* NHibernate *cough* 无法从 Person 到 OrderHeader 执行 LEFT JOIN (.DefaultIfEmpty)。实现从 Person 到 OrderHeader 的 LEFT JOIN 的唯一方法是将 OrderHeader 作为集合映射到 Person。
我是否应该允许基础设施问题(例如,通过 Linq 的 .DefaultIfEmpty 通过使 OrderHeader 成为 Person 的集合来促进从 Person 到 OrderHeader 的 LEFT JOIN)打破关于何时应该只有实体必须成为聚合根的规则?
如果我们不将 OrderHeader 作为一个集合映射到 Person,那么如果我们需要在 NHibernate 上从 Person 到 OrderHeader 进行 LEFT JOIN(扁平化结果,不是分层的,因此需要使用 LEFT JOIN),剩下的唯一选择是使用 QueryOver。QueryOver 与 Linq 相比,写起来非常繁琐。
如果我们从 Person 到 OrderHeader 手动执行 LEFT JOIN(即通过 Linq 的连接和 .DefaultIfEmpty),则无法在 NHibernate 的 Linq 上使用 .DefaultIfEmpty(LEFT JOIN 功能),如果我们在 NHibernate 上执行手动 LEFT JOIN,.DefaultIfEmpty 会抛出异常, NHibernate 的 Linq 上的 LEFT JOIN 必须通过集合和 .DefaultIfEmpty 完成。
如果偶尔进行(根据需要),是否打破聚合根规则是一个务实的选择?例如,我是否应该将 OrderHeader 作为集合映射到 Person,以便通过 Linq 促进从 Person 到 OrderHeader 的 LEFT JOIN?
编辑
北风数据库示例。当我们需要报告所有有订单的客户,包括那些没有订单的客户时(例如,PARIS)
CustomerID OrderID
OTTIK | 10407
OTTIK | 10684
OTTIK | 10554
PARIS |
PERIC | 10502
PERIC | 10474
PERIC | 10995
PERIC | 10354
PERIC | 11073
PERIC | 10322
,我们需要做一个 LEFT JOIN:
select c.CustomerID, o.OrderID
from customers c
left join orders o on c.CustomerID = o.CustomerID
order by c.CustomerID
这可以通过 Linq 的 join 和 .DefaultIfEmpty() 来完成。但是 NHibernate 的 Linq 不能对手动 Linq 连接的结果执行 .DefaultIfEmpty,它会引发异常。NHibernate 的 DefaultIfEmpty 只能应用于集合。但是我觉得将集合映射到不是聚合根的东西违反了 DDD 聚合根规则。而且这样做,所有实体,如 Person(客户是另一个例子)都可能包含所有实体的集合,因为每个表都有一个 CreatedByPerson 引用。
@DanielSchilling:
我也很惊讶(以一种好的方式),从 OrderItem 引用 OrderHeader 违反了 DDD。我们是否有某种白皮书或 Martin Fowler 的文章对此进行了阐述?我认为从子实体引用父实体不被视为基础设施问题,因此被视为 DDD。