DDD - 乐观并发属性(etag或timestamp)是否应该成为域的一部分?

时间:2018-03-16 08:01:24

标签: domain-driven-design

从理论上讲,如果我们在聚合根级别上实现乐观并发(在AR中更改实体更改AR上的版本),并且假设我们使用时间戳作为版本属性(仅为了简单起见) - 时间轴应该是AR上的属性还是应该它是一方面读取模型的一部分,另一方面(例如,更新)是应用程序服务的单独参数,如:

[伪]

public class AppService{
.
.
.
   public void UpdateSomething(UpdateModelDTO model, int timestamp)
   {
      repository.GetModel(model.Identifier);
      model.UpdateSomething(model.something);
      repository.ConcurrencySafeModelUpdate(model, timestamp);
   }
}

我看到两者的利弊,但想知道哪个是书本解决方案?

[UPDATE]

要回答来自@ guillaume31的问题,我希望通常情况:

  1. 在读取时,将读取版本标识符并将其发送到客户端
  2. 在更新时,客户端发回标识符,如果版本标识符不相同,则存储库会返回某种错误。
  3. 我不知道它是否重要,但我想承担创建/更新版本标识符本身的责任到我的数据库系统。

3 个答案:

答案 0 :(得分:2)

我假设,否则你不会问这个问题,你使用你的域模型作为数据模型(即Hibernate实体),那么你已经在你的域模型中引入了基础设施问题,所以我建议继续并将时间戳添加到AR。

答案 1 :(得分:1)

除了与业务相关的问题外,Aggregate不应该关心任何其他问题。它应该是纯粹的,没有任何基础设施问题。

数据库/持久性中的version列是基础结构问题,因此不应在Domain层的Aggregate类中反映出来。

P.S。使用时间戳进行乐观锁定很奇怪;你最好使用一个整数,每当一个Aggregate发生变异时,该整数会增加,并且当执行save时,它应该具有(loaded-version + 1)。

public void UpdateSomething(UpdateModelDTO model)
{
     (model, version) = repository.GetModel(model.Identifier);
     model.UpdateSomething(something);
     repository.ConcurrencySafeModelUpdate(model, version + 1);
}

答案 2 :(得分:0)

没有书本解决方案。有时,您的聚合中已经有一个适合该角色的字段(例如LastUpdatedOn),有时您可以将其设为非域数据。出于性能原因,最好选择该字段作为获取聚合的同一查询的一部分。

某些ORM提供检测并发冲突的工具。某些DBMS可以自动为您创建和更新版本列。您应该在特定堆栈中寻找有关乐观并发的指导原则。