希望这个虚构的例子能说明我的问题:
假设您正在编写一个跟踪软件产品投诉的系统,以及该产品的许多其他属性。在这种情况下,SoftwareProduct是我们的聚合根,而投诉是只能作为产品子项存在的实体。换句话说,如果软件产品从系统中删除,投诉也是如此。
在系统中,有一个类似于网页的仪表板,它显示单个SoftwareProduct的许多不同方面。仪表板中的一个部分以时尚网格显示投诉列表,仅显示每个投诉的一些非常高级别的信息。当管理员类型用户选择其中一个投诉时,会将其定向到编辑屏幕,以便他们编辑单个投诉的详细信息。
问题是:编辑屏幕检索单个投诉的最佳方式是什么,以便可以显示它以进行编辑?请记住,我们已将SoftwareProduct建立为聚合根,因此不应允许直接访问Complaint。此外,系统正在使用NHibernate,因此急切加载是一个选项,但我的理解是,即使通过SoftwareProduct急切加载单个投诉,只要访问Complaints集合,就会加载其余的集合。那么,如何通过SoftwareProduct获得单一投诉,而不会产生加载整个投诉集合的开销?
答案 0 :(得分:5)
这有点涉及语义和宗教信仰,但在编辑投诉的背景下,投诉是根本对象。编辑投诉时,父对象(软件产品)并不重要。它显然是一个具有独特身份的实体。因此,您将拥有专门用于保存更新投诉等的服务/存储库。
另外,我认为你有点过于消极。投诉? “评论”怎么样?还是“ConstructiveCriticisms”?
答案 1 :(得分:1)
@Josh,
我不同意你所说的,尽管我注意到有些人为了性能而这样设计他们的“Web”应用程序,而不是基于域模型本身。
我也不是DDD专家,但我确信你已经阅读了传统的Order和OrderItem示例。所有DDD书都说OrderItem属于Order聚合,Order是聚合根。
根据您的意思,OrderItem不再属于Order聚合,因为用户可能希望直接编辑OrderItem,其中Order不重要(就像编辑Complaing一样,其父项软件产品不重要)。而且你知道如果遵循这种方法,就不能强制执行任何订单不变量,这对于电子商务系统来说非常重要。
任何人都有更好的方法吗?
MOSH
答案 2 :(得分:1)
回答你的问题:
聚合用于保持一致性。例如,如果从父项(聚合根)添加/修改/删除子对象导致不变量中断,那么您需要在那里进行聚合。
但是,在您的问题中,我认为SoftwareProduct和Compliant属于两个单独的聚合,每个聚合都是它们自己的聚合的根。您无需加载SoftwareProject和分配给它的所有N个投诉,只需添加新的投诉即可。对我来说,在添加新投诉时,您似乎没有要评估的任何业务规则。
因此,总而言之,创建2个不同的存储库:SoftwareProductRepository和ComplaintRepository。
此外,删除SoftwareProduct时,可以使用数据库关系级联删除并删除关联的投诉。为了数据完整性,这应该在您的数据库中完成。您不需要在域模型中控制它,除非除了删除链接对象之外还有其他不变量。
希望这有帮助,
MOSH
答案 3 :(得分:0)
我将NH用于其他业务环境,但与您的类似实体关系。我不明白你为什么这么说:
请记住我们已经有了 将SoftwareProduct建立为 聚合根,因此直接 不应该访问投诉 允许
我在我的Article
和Publisher
实体中有这个,如果Publisher
不再存在,那么所有依赖的Artcle
实体也是如此。我允许自己直接访问每个Article
和各个实体的Publisher
个集合。在Article
班级的数据库/地图中,Publisher
是其中一个成员,无法接受Null
。
注意详细说明你和我之间的区别?
对不起,这不是一个直接的答案,但是太长了,无法添加为评论。
答案 4 :(得分:0)
我同意莫什的观点。这两个实体中的每一个都有自己的聚合根。让我在现实生活中解释一下。假设一家公司开发了一个软件。这个软件有一些错误,让你烦恼。你要去公司并从这个问题中了解他们。这家公司为您提供一份表格供您填写。
此表单有一个字段 - 部分 - 表示软件名称和描述。此外,它还有一些适合您投诉的部分。此表格与软件手册相同吗?不是。这是与软件相关的表格。它不是软件。这个表格有没有ID?是。它有。换句话说,您可以在第二天致电公司并向运营商询问您的投诉信。很明显,运营商会询问您的ID。
这个证据表明这种形式有自己的实体,不能与软件本身混淆。两个不同实体之间的任何关系并不意味着其中一个属于另一个。