我希望了解人们可能采取了哪些方法来检测作为其聚合一部分的实体的变化。我有一些有用的东西,但我并不为此而疯狂。基本上,我的存储库负责确定聚合根的状态是否已更改。假设我有一个聚合根调用Book
和一个在聚合内调用的实体Page
。ABook
包含一个或多个Page
实体,存储在一个Pages
集合中。
首先,插入与更新场景是通过检查聚合根及其实体来确定键的存在来完成的。如果该键存在,则假定该对象已在某一时间保存到基础数据源。这使它成为更新的候选者;但仅基于实体的这一点并不能确定。使用聚合根,答案是显而易见的,因为只有一个并且它是唯一的入口点,可以假设密钥的存在将决定操作。在我的情况下,将聚合根本身再次保存回来是一个可接受的方案,以便我可以捕获修改日期。
为了帮助实体本身的这种行为,我的EntityBase
类包含两个简单的属性:IsUpdated()
, IsDeleted()
. 这两个都默认为false。我不需要知道它是否是新的,因为我可以根据密钥的存在来做出决定,如前所述。实现上的方法(在本例中为 Page)将具有将支持数据集更改IsUpdated()
为 true 的每个方法。
因此,例如,Page 有一个方法调用UpdateSectionName()
,它更改属性的支持值SectionName
,它是只读的。这种方法一直被使用,因为它允许在执行该数据设置的方法(防止实体进入无效状态)中使用验证器的逻辑连接点。最终结果是我必须this.IsUpdated() = true;
在方法的末尾放一个。
当聚合根被发送到存储库Save()
(逻辑切换到Insert()
或Update()
操作)时,它可以遍历 中的Pages
集合Book
,查找具有以下三种情况之一的任何页面:
- 没有钥匙。
Page
将插入没有密钥的 A。 IsDeleted = true;
删除胜过更新,删除将被提交 - 忽略Page
.IsUpdated = true;
将为页面提交更新。
这样做可以防止我盲目地更新 Pages 集合中的所有内容,例如,如果 Book 中有数百个 Page 实体,这可能会令人生畏。我一直在考虑检索这本书的副本,并进行比较并仅提交检测到的更改(基于存在和/或比较的插入、更新和删除),但这似乎是一种非常健谈的方式.
主要缺点是开发人员必须记住在实体的每个方法中设置 IsUpdated。忘记一个,它将无法检测到该值的变化。我玩弄了某种自定义后备存储的想法,它可以透明地为更改添加时间戳,这反过来又可以创建IsUpdated
一个只读属性,存储库可以使用它来聚合更新。
存储库正在使用工作单元模式实现,该实现基于聚合根添加到它时生成的时间戳。由于可能有多个实体排队等待操作,因此在执行实体所属的聚合根操作后立即汇总并执行实体操作。我可以看到更进一步并创建另一个工作单元来处理实体操作并将它们基于实体中使用的某种事件跟踪(这就是我假设市场上的一些 ORM 产品完成的方式类似的功能级别)。
不过,在我继续朝这个方向前进之前,我很想听听有关这方面的想法/建议/经验。
编辑:一些可能有助于了解的附加信息:
- 我目前使用的语言是 C#,尽管我试图尽可能多地保留特定于语言的信息,因为这更多是理论上的讨论。
- 存储库/服务/实体/等的代码。是基于 Tim McCarthy 在他的书“使用 C# 的 .NET 域驱动设计”和CodePlex上的支持代码中的概念。它提供了对所采用方法类型的可运行理解,尽管我正在使用的内容在很大程度上已经从头开始重写。