Domain driven design DDD一个聚合,两个可能的数据源

Domain driven design DDD一个聚合,两个可能的数据源,domain-driven-design,Domain Driven Design,我有一个场景,我们决定在内部拉一些功能,这是我们很久以前就应该做的,因为它是我们核心领域的一部分。作为转换的一部分,我们将暂时与外部服务合作,以存储和检索小部件s,或者根据类型使用我们的数据库。当与本地数据库交互时,我们将使用乐观并发,它将向我们的小部件添加一个版本字段,该字段在与外部服务交互时不存在 这里的规范领域驱动设计解决方案是什么?抽象这一点的最佳方式是什么?应该在哪里实现?我的第一反应是在应用程序服务层中实现一个抽象工厂模式,但有人可能会认为这一切都可以抽象到存储库中。这样,当我们退出

我有一个场景,我们决定在内部拉一些功能,这是我们很久以前就应该做的,因为它是我们核心领域的一部分。作为转换的一部分,我们将暂时与外部服务合作,以存储和检索
小部件
s,或者根据类型使用我们的数据库。当与本地数据库交互时,我们将使用乐观并发,它将向我们的
小部件
添加一个
版本
字段,该字段在与外部服务交互时不存在


这里的规范领域驱动设计解决方案是什么?抽象这一点的最佳方式是什么?应该在哪里实现?我的第一反应是在应用程序服务层中实现一个抽象工厂模式,但有人可能会认为这一切都可以抽象到存储库中。这样,当我们退出外部服务时,消费者就不需要做出改变。因为我们使用的是聚合设计,并且没有过于复杂的用例,所以我们不需要担心工作单元或类似的东西。事务性问题完全在存储库中维护。

由于存储库负责存储抽象,我认为存储库也有责任协调多个存储

您可以实现类似的功能:

现在,如果您必须支持
expectedVersion
,您可以在接口的合同中明确指出,
expectedVersion
可能不受所有实现的支持,并且会抛出或根本不会被接受

“实体ID+版本上会有一个唯一的约束 号码。”

这适用于并发冲突,但无论如何也不能防止非并发的丢失更新,例如

  • 客户端C1在屏幕上加载小部件W(v1)

  • 客户端C2在屏幕上加载小部件W(v1)

  • 客户端C2进行更改和保存(例如更新说明)

  • 存储库在内存中加载W(v1)并保存W(v2)

  • 客户端C1进行更改和保存(例如更新说明)

  • 存储库在内存中加载W(v2)并保存W(v3)


  • 最后,C2的
    说明
    更新悄无声息地丢失了。通常,您可以通过随命令一起发送预期版本来解决此问题。

    现在如何确保两个数据存储之间的原子性?您不能将AR存储在两个单独的DBs中。很明显,整个聚合存储在一个位置,但根据类型,这可能是两个数据存储中的一个。这还没有建立-只是想看看在增加增量价值的同时简化转换的方法。如果不支持乐观锁定,外部存储有什么可用的锁定机制?这是一个全面的第三方
    Widget
    服务-我们无法控制如何处理并发。我们有解决办法,但我认为这超出了范围,或者不是这个问题的真正目的。不过问题很好!你是真的在写API还是只是在读?如果您写信给我,他们似乎需要提供某种锁定机制,并且您的应用程序必须知道这一点,否则可能会发生丢失的更新。是的,关于并发“丢失”更新,这是一个很好的观点。有时,根据您在特定领域中对这类事情的容忍度,只要命令/变异在给定模型的当前状态下是有效的(当前是您在请求进入服务时检索到的任何内容),您就可以不关心预期的版本。您可能还想确保版本是连续的,但并发性的目的再次超出了问题的范围。我认为您提出了一个相当有说服力的论点-这一点让我怀疑是否存在,这里有一个更好的解决方案是,我们现在正在调用存储库中的外部服务。如果我们有良好的聚合设计,我们通常不应该有跨越多个存储库的调用,但是如果我们这样做了,并且我们必须实现类似于工作单元的东西,那么我们可能会调用外部服务,从而阻止打开的事务。这不是AR边界错了,分布式的是AR存储。只要每个AR是内部的或外部的,它就有意义,但一个AR不应该被分割到不同的存储中。另一层上的DB和您的外部服务之间没有区别。两者都可以被视为外部服务。是的,这是公平的——我向我的同事提出了同样的观点。我很想把这些完全分开来处理,但太多的工作都是一次性的。