我理解聚合根的概念,我知道一个聚合根必须通过标识(http://dddcommunity.org/wp-content/uploads/files/pdf_articles/Vernon_2011_2.pdf)引用另一个,所以我不知道如何强制实体框架之间添加外键约束两个聚合?
假设我有一个简化的域名:
public class AggregateOne{
[Key]
public Guid AggregateOneID{ get; private set;}
public Guid AggregateTwoFK{get; private set;}
/*Other Properties and methods*/
}
public class AggregateTwo{
[Key]
public Guid AggregateTwoID{get; private set;}
/*Other Properties and methods*/
}
使用此域设计,Entity Framework不知道AggregateOne和AggregateTwo之间存在关系,因此生成的数据库中没有外键。
答案 0 :(得分:5)
在DDD中,EF不存在。域关系与数据库关系不同。不要试图将EF与域建模混合,它们不能一起工作。简而言之,你所拥有的不是DDD,只是普通的旧关系数据库伪装成DDD。 EF将由存储库使用,并且会关注持久化一个聚合根(AR)。
两个AR可以一起工作,但是您需要根据域对流程建模。 EF是应用程序的数据库,它关注持久性问题,不应该关心域。持久性完全是关于存储而不是反映域关系(EF实体不是域实体,尽管它们可以具有相同的名称并且看起来相似。重要的细节是两者都属于不同的层并处理不同的问题)。域存储库只关心以可以在更改时轻松恢复的方式保留AR。如果需要将更多AR保持在一起,请接受最终的一致性并学习如何使用服务总线和传奇。它将大大简化您的生活(将其视为工作单元模式的一种实现)。
对于查询,最干净和优雅的方法是生成/更新适合查询用例的读取模型,这通常在域事件告诉“世界”域中发生了某些变化之后完成。
正确执行DDD并不容易陷入陷阱,并且相信您实际使用DDD,而实际上您只是使用DDD术语进行CRUD。如果你喜欢简单的生活,IMO CQRS也是必备的DDD。
理解域名而不是急于求成,理解有界的上下文,模拟域概念及其用例(非常重要!!!),在需要时定义存储库接口,并且只在没有任何内容时实现存储库还剩下去做(真正的回购,同时你可以使用假存储库中的假存储 - 它们实现起来非常快,你的应用程序被解耦意味着它不应该关心如何实现持久性,对吧?) 。我知道这听起来很奇怪,但这就是你知道你有一个可维护的DDD应用程序。
最后实现存储库的目的是将应用程序与持久性细节真正分离,并定义应用程序对持久性的期望(存储库方法)。一旦定义,您可以编写测试:D然后实现存储库。奖励是你只关注repo实现是隔离,当所有测试通过时,你知道一切正常。
答案 1 :(得分:0)
为什么要有两个完全不同的对象?为什么不通过域接口将您的实体公开为域对象? 在这种情况下,让您的实体也充当域对象,其实现细节整齐地隐藏在界面后面没有问题。
另一个用EF表示聚合根的简洁方法是确保外键列也构成从属实体的主键。在您的情况下,这意味着AggregateOneId和AggregateTwoFk将组成AggregateOne的复合主键。这将确保EF不需要存储库来删除AggregateOne上的实例,只要它从AggregateTwo集合中删除它就会被正确标记为从数据库中删除(如果你没有&#39 ; t有这样的密钥你需要从AggregateOne集中删除它,因为EF会抛出一个异常而不理解开发人员应该删除AggregateOne的意图。