在DDD中调用repository.update的位置?

时间:2013-01-10 10:51:19

标签: c# domain-driven-design ddd-repositories

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

我的问题清楚了吗? :) 先感谢您 最好 月桂精

4 个答案:

答案 0 :(得分:7)

  

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

在陈规定型的DDD架构中,存储库通常由应用程序服务调用。应用程序服务是一个类,它用作封装域的facade,并通过编排域对象,存储库和其他服务来实现域用例。

我不熟悉您的域名,但假设有一个用例将StateQuadrant中的Field转移到另一个Field。正如您所说,FieldApplicationService是AR。因此,您有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); } }

Update

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

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

在您的情况下,如您所述,没有更改跟踪,因此需要显式调用更新,并由存储库实现来处理此问题。如果使用SQL Server作为数据库,则存储库上的Field方法只需将{{1}}的所有属性发送到存储过程,该存储过程将根据需要更新表。

答案 1 :(得分:4)

聚合根(AR)更新了。使用消息驱动的体系结构,某个地方是一个命令处理程序,但让我们说通用的是一个服务。服务从存储库获取AR,调用相关方法然后将AR保存回存储库。

AR不知道存储库,它不是它的关注点。然后,存储库将所有AR修改作为一个工作单元保存(即全部或全部)。 Repo如何做到这一点,这取决于你如何决定你的持久战略。

如果您正在使用事件采购,则AR会生成事件,而Repo将使用这些事件来保持AR状态。如果采用更常见的方法,那个AR应该将状态数据暴露为属性。它被称为纪念品模式。存储库在一次提交中保留该数据。

有一件事是肯定的:在处理Domain对象时,千万不要想到持久性细节。那就是不要将域耦合到ORM或某些特定于db的东西。

答案 2 :(得分:4)

“应用程序代码”应该调用存储库。如何托管应用程序代码是基础架构问题。可以托管应用程序代码的一些示例是WCF服务,Winforms / WPF应用程序或Web服务器。

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

以下是一个例子:

域项目

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.
}

如果您需要对多个聚合根进行事务处理,以便在全部或全部的基础上进行更改,那么您应该查看工作单元模式。

希望这有助于澄清事情!

答案 3 :(得分:3)

我的解决方案是聚合根将外部的事件处理程序引发一些事件。那些事件处理程序将调用存储库来更新数据库。您还需要一个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);
    }
}