我正在尝试使用ASP.NET MVC项目首次实现DDD,而我正在努力解决一些问题。
我有2个相关实体,一个公司和一个供应商。我最初的想法是公司是一个集合根,供应商是公司的价值对象。所以我有一个公司的存储库,没有供应商的存储库。
但是当我开始构建我的应用程序时,我最终需要为供应商单独列出,创建和更新表单。这个名单很容易我可以打电话给Company.Suppliers,而且创建很糟糕我可以做Company.Suppliers.Add(供应商),但更新让我很头疼。由于我只需要一个实体,而且我无法将它完全固定在表单之间的内存中,我最终需要重新获取公司和所有供应商并找到我需要绑定到它的那个并再次修改它并坚持下去回到db。
如果我有供应商的存储库,我真的只需要做一个GetOne。我可以通过向我的公司或CompanyRepository添加GetOneSupplier来添加一些工作,但这看起来很垃圾。
所以,我真的想知道它是否真的是一个价值对象,而不是一个完整的域实体本身。
tldr;
是否需要单独的列表/创建/更新视图/页面,表明实体应该是它自己的根?
答案 0 :(得分:35)
根据您的术语,我假设您正在根据Eric Evans的书执行DDD。听起来你已经发现了最初的建模问题并且你是对的。
你提到你认为供应商是Value Object
......我建议不是。 Value Object
主要由其属性标识。例如,日期“2009年9月30日”是值对象。为什么?因为具有不同月/日/年组合的所有日期实例都是不同的日期。具有相同月/日/年组合的所有日期实例被视为相同。我们永远不会因为它们是相同的而交换我的“2009年9月30日”: - )
另一方面,Entity
主要由其“ID”标识。例如,银行帐户有ID - 它们都有帐号。如果银行有两个帐户,每个帐户有500美元,如果他们的帐号不同,那么他们也是。他们的属性(在这个例子中,他们的平衡)不识别它们或暗示平等。我敢打赌,即使他们的余额相同,我们也会争论交换银行账户: - )
因此,在您的示例中,我会考虑供应商Entity
,因为我认为每个供应商主要由其ID而不是其属性来识别。我自己的公司与世界上另外两家公司共享其名称 - 但我们并非都可以互换。
我认为你的建议是,如果你需要CRUDing一个对象的视图,那么Entity
可能是一般的经验,但是你应该更多地关注一个对象与其他对象的不同之处:属性或ID。
现在,就Aggregate Root
而言,您希望专注于对象的生命周期和访问控制。考虑一下我的博客上有很多帖子,每个帖子都有很多评论 - Aggregate Root
(s)在哪里?让我们从评论开始。没有帖子发表评论是否有意义?你会创建一个评论,然后找一个帖子并将其附加到它?如果您删除帖子,是否会保留其评论?我建议帖子是Aggregate Root
,有一个“叶子” - 评论。现在考虑博客本身 - 它与帖子的关系类似于帖子和评论之间的关系。在我看来,它也是一个Aggregate Root
,有一个“叶子” - 帖子。
因此,在您的示例中,公司和供应商之间是否存在强大的关系,如果您删除公司(我知道......您可能只有一个公司实例),您还会删除其供应商吗?如果你删除“星巴克”(美国的一家咖啡公司),它的所有咖啡豆供应商都不复存在吗?这一切都取决于您的域名和应用程序,但我建议您的Entities
都不是Aggregate Roots
,或者更好的方式来考虑它们是因为它们是聚合根,每个都没有“叶子“(没有什么可聚合的)。换句话说,公司无法控制对供应商生命周期的访问或控制。它只与供应商(或许多对多)建立了一对多的关系。
这将我们带到Repositories
。 Repository
用于存储和检索Aggregate Roots
。你有两个(从技术上讲,他们没有聚合任何东西,但比说“存储库存储聚合根或聚合中不是叶子的实体”更容易),因此你需要两个Repositories
。一个用于公司,一个用于供应商。
我希望这会有所帮助。也许埃里克埃文斯潜伏在这里,并会告诉我我偏离了他的范例。
答案 1 :(得分:1)
对我来说听起来很简单 - 供应商应该拥有自己的存储库。如果某个实体可以在模型中独立存在,那么它应该是一个根实体,否则你最后会在最后进行重构,这是多余的工作。
Root实体总是比值对象更灵活,尽管前面有额外的实现工作。我发现随着模型的发展,模型中的值对象随着时间的推移变得越来越少,并且保留值对象的实体通常是从第一天开始就可以逻辑限制的实体。
如果公司共享供应商,那么将供应商作为根实体也会消除数据冗余,因为您不会复制每个公司的供应商定义,而是共享参考,并且公司和供应商之间的关联也可以是双向的,这可能会产生更多的好处。