在DDD中调用repository.update的位置

本文关键字:update 位置 repository 调用 DDD | 更新日期: 2023-09-27 17:51:09

我有一个真实的场景,它是一个完美的领域模型设计。它是一个有多个象限的场,每个象限上都有不同的状态。所以我的总根是田野。现在我有一个重要的问题:我想要一个持久的忽略域模型,我认为这是有意义的。那么,我应该在哪里调用存储库方法的更新呢?不在领域模型中,对吧?那么,当没有此对象的更改跟踪代理并且实体中不应调用存储库时,聚合根子实体应如何在数据库中更新呢?或者我误解了领域模型模式?

我的问题清楚吗?:(提前谢谢最好的月桂醇

在DDD中调用repository.update的位置

那么,我应该在哪里调用存储库方法的更新呢?

在传统的DDD体系结构中,存储库通常由应用程序服务调用。应用程序服务是一个类,它充当封装域的门面,并通过协调域对象、存储库和其他服务来实现域用例。

我不熟悉您的域,但假设有一个用例将StateField中的一个Quadrant转移到另一个。正如你所说,Field就是AR。所以你会有一个FieldApplicationService引用FieldRepository:

public class FieldApplicationService
{
    readonly FieldRepository fieldRepository;    
    public void ShiftFieldState(int fieldId, string quadrant, string state)
    {
          // retrieve the Field AR
          var field = this.fieldRepository.Get(fieldId);
          if (field == null)
              throw new Exception();
          // invoke behavior on the Field AR.
          field.ShiftState(quadrant, state);
          // commit changes.
          this.fieldRepository.Update(field);
    }
}

应用程序服务本身非常瘦。它不实现任何域逻辑;它只为域逻辑的执行编排和设置阶段,域逻辑包括访问存储库。所有依赖于域的代码,如表示层或服务,都将通过此应用程序服务调用域功能。

存储库可以通过多种方式实现。它可以使用像NHibernate这样的ORM,在这种情况下,会内置更改跟踪,通常的方法是提交所有更改,而不是调用显式更新。NHibernate还提供了一个工作单元,允许对多个实体的更改作为一个实体提交。

在您的案例中,正如您所说,没有更改跟踪,因此需要明确调用更新,这取决于存储库实现来处理。如果使用SQL Server作为数据库,则存储库上的Update方法可以简单地将Field的所有属性发送到存储过程,该存储过程将根据需要更新表。

聚合根(AR(在此处更新。使用消息驱动的体系结构,某处是一个命令处理程序,但就一般用途而言,它是一个服务。该服务从存储库中获取AR,调用相关方法,然后将AR保存回存储库。

AR不知道存储库,这不是它关心的问题。然后,Repository将所有AR修改保存为一个工作单元(要么全部保存,要么不保存(。回购如何做到这一点,好吧,这取决于你如何决定你的持久性策略。

如果您正在使用事件源,则AR会生成事件,Repo将使用这些事件来保持AR状态。如果你采取一种更常见的方法,AR应该在某个地方将状态数据作为属性公开。它被称为纪念图案。存储库在一次提交中保持该数据。

但是有一点是肯定的:在处理Domain对象时,永远不要考虑持久性细节。也就是说,不要将域与ORM或某些特定于数据库的东西耦合。

"应用程序代码"应该调用存储库。如何托管应用程序代码是一个基础结构问题。应用程序代码托管方式的一些示例是WCF服务、Winforms/WPF应用程序或Web服务器。

存储库实现负责跟踪对聚合根及其子实体的更改,并将其保存回数据库。

这里有一个例子:

域项目

public DomainObject : AggregateRootBase //Implements IAggregateRoot
{
    public void DoSomething() { }
}
public IDomainObjectRepository : IRepository<DomainObject>, IEnumerable
{
    DomainObject this[object id] { get; set; }
    void Add(DomainObject do);
    void Remove(DomainObject do);
    int IndexOf(DomainObject do);
    object IDof(DomainObject do);
    IEnumerator<DomainObject> GetEnumerator();
}

实施项目

public SqlDomainObjectRepository : List<DomainObjectDataModel>, IDomainObjectRepository
{
    //TODO: Implement all of the members for IDomainObjectRepository
}

应用程序项目

public class MyApp
{
    IDomainObjectRepository repository = //TODO: Initialize a concrete SqlDomainObjectRepository that loads what we need.
    DomainObject do = repository[0]; //Get the one (or set) that we're working with.
    do.DoSomething(); //Call some business logic that changes the state of the aggregate root.
    repository[repository.IDof(do)] = do; //Save the domain object with all changes back to the db.
}

如果您需要对多个聚合根进行事务化更改,以便在要么全有要么全无的基础上进行更改,那么您应该研究工作单元模式。

希望这有助于澄清事情!

我的解决方案是聚合根将向外部的事件处理程序引发一些事件。这些事件处理程序将调用存储库来更新数据库。您还需要一个ServiceBus来注册和调度事件。参见我的示例:

public class Field: AggregateRoot
{
    public UpdateField()
    {
         // do some business
         // and trigger FieldUpdatedEvent with necessary parameters
         ....
         // you can update some quadrants
         // and trigger QuadrantsUpdatedEvent with necessary parameters
    }
}
public class FieldEventHandlers: EventHandler 
{
    void Handle (FieldUpdatedEvent e)
    {
         repository.Update(e.Field);
    }
}
public class QuadrantEventHandlers: EventHandler 
{
    void Handle (QuadrantsUpdatedEvent e)
    {
         repository.Update(e.Quadrant);
    }
}