检测聚合根中实体的更改

时间:2009-09-14 14:03:02

标签: c# architecture persistence ddd-repositories

我希望了解人们可能采取了哪些方法来检测作为其聚合的一部分的实体中的更改。我有一些有用的东西,但我并不为此感到疯狂。基本上,我的存储库负责确定聚合根的状态是否已更改。假设我在聚合中有一个名为Book的聚合根和一个名为Page的实体。 Book包含一个或多个Page实体,存储在Pages集合中。

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

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

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

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

  1. 没有钥匙。将插入没有密钥的Book
  2. Page删除优先于更新,删除将被提交 - 忽略IsDeleted = true;的任何更新。
  3. Page将为页面提交更新。
  4. 这样做可以防止我盲目地更新Pages集合中的所有内容,例如,如果Book中有几百个Page实体,这可能会让人望而生畏。我一直在考虑检索本书的副本,并进行比较并仅提交检测到的更改(基于存在和/或比较的插入,更新和删除),但它似乎是一种非常繁琐的方式来实现它

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

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

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

    修改:可能有助于了解的一些其他信息:

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

1 个答案:

答案 0 :(得分:1)

简而言之,我的回答是我选择了我的建议。它确实有效,但我确信还有改进的余地。这些变化实际上花了很少的时间,所以我觉得在这种情况下我没有离开KISS或YAGNI校长太远。 : - )

我仍然觉得在操作方面存在计时相关问题的空间,但我应该能够在存储库实现中解决这些问题。不是理想的解决方案,但我不确定是否值得重新发明轮子以纠正可以在更短的时间内避免的问题。