检测聚合根内实体的变化

Jos*_*ris 5 c# architecture persistence ddd-repositories

我正在寻找人们可能采取哪些方法来检测作为其聚合一部分的实体的变化。我有一些有用的东西,但我并不为之疯狂。基本上,我的存储库负责确定聚合根的状态是否已更改。让我们假设我有一个被调用的聚合根Book和一个Page在聚合内被调用的实体。ABook包含一个或多个Page实体,存储在一个Pages集合中。

首先,插入与更新场景是通过检查聚合根及其实体以确定键的存在来完成的。如果该键存在,则假定该对象曾一度保存到基础数据源中。这使它成为更新的候选者;但对于实体而言,它并不是确定的。对于聚合根,答案是显而易见的,因为只有一个并且它是入口的奇异点,所以可以假设键的存在将决定操作。在我的情况下,再次保存聚合根本身是一个可以接受的场景,以便我可以捕获修改日期。

为了帮助实体本身实现这种行为,我的EntityBase类包含两个简单的属性:IsUpdated(), IsDeleted()。这两个都默认为false。我不需要知道它是否是新的,因为我可以根据密钥的存在来做出决定,如前所述。实现上的方法(在本例中为 Page)将具有将支持数据集更改IsUpdated()为 true 的每个方法。

因此,例如,Page 有一个方法被调用UpdateSectionName(),该方法更改SectionName属性的后备值,该方法是只读的。这种方法被一致使用,因为它允许在执行该数据设置的方法中使用验证器的逻辑连接点(防止实体进入无效状态)。最终结果是我必须this.IsUpdated() = true;在方法的末尾放置一个。

当聚合根被发送到存储库中Save()(逻辑切换到 anInsert()Update()操作)时,它可以遍历 中的Pages集合Book,查找具有以下三种情况之一的任何页面:

  1. 没有钥匙。Page将插入没有键的A。
  2. IsDeleted = true;删除胜过更新,删除将被提交 - 忽略Page.
  3. IsUpdated = true; 将为页面提交更新。

这样做可以防止我盲目地更新 Pages 集合中的所有内容,例如,如果 Book 中有数百个 Page 实体,这可能会令人生畏。我一直在考虑检索这本书的副本,并进行比较并仅提交检测到的更改(根据存在和/或比较进行插入、更新和删除),但这似乎是一种非常健谈的方法.

主要缺点是开发人员必须记住在实体中的每个方法中设置 IsUpdated。忘记一个,它将无法检测到该值的变化。我曾考虑过某种自定义后备存储的想法,它可以透明地时间戳更改,这反过来可以使IsUpdated存储库可以用来聚合更新的只读属性。

存储库正在使用一个工作单元模式实现,它的操作基于将聚合根添加到它时生成的时间戳。由于可能有多个实体排队等待操作,因此在执行实体所属的聚合根操作后立即汇总并执行实体操作。我可以看到更进一步并创建另一个工作单元来处理实体操作并将它们基于实体中使用的某种事件跟踪(这就是我假设市场上的某些 ORM 产品完成类似级别的功能)。

不过,在我继续朝着这个方向前进之前,我很想听听有关这方面的想法/建议/经验。

编辑:一些可能有助于了解的其他信息:

  1. 我正在使用的当前语言是 C#,尽管我试图保留尽可能多的特定于语言的信息,因为这更多是理论讨论。
  2. 存储库/服务/实体/等的代码。基于 Tim McCarthy 在他的书“.NET Domain-Driven Design with C#”中的概念和CodePlex上的支持代码。它提供了对所采用方法类型的可运行理解,尽管我正在使用的内容在很大程度上已从头开始重写。

Jos*_*ris 2

简而言之,我的回答是我按照我的建议去做。它正在发挥作用,尽管我确信还有改进的空间。这些改变实际上只花了很少的时间,所以我觉得在这种情况下我并没有偏离 KISS 或 YAGNI 原则太远。:-)

我仍然认为操作上的计时相关问题还有空间,但我应该能够在存储库实现中解决它们。这不是理想的解决方案,但我不确定是否值得重新发明轮子来纠正一个可以在比修复时间更短的时间内避免的问题。