Где вызвать репозиторий.обновление в DDD?

У меня есть реальный сценарий, который является идеальным дизайном модели домена. Это поле имеет несколько квадрантов с различными состояниями в каждом квадранте. Итак, мой совокупный корень-это поле. Теперь у меня есть один важный вопрос.: Я хочу иметь настойчивую невежественную модель домена, которая, я думаю, имеет смысл. Итак, где я должен вызвать обновление методов репозитория? не в доменной модели, верно? Итак, как должны обновляться дочерние сущности aggregate root в базе данных, когда нет изменений прокси отслеживания этих объектов и репозитория не должны вызываться в сущностях? Или я неправильно понимаю шаблон модели домена?

мой вопрос ясен? :) Заранее спасибо лучший Лорин!--1-->

4 ответов


Итак, где я должен вызвать обновление методов репозитория?

в стереотипной архитектуре DDD репозиторий обычно вызывается сервис приложения. Службы приложений-это класс, который служит в качестве фасад инкапсуляция домена и реализует домен использует случаи путем оркестровки объектов домена, репозиториев и других служб.

Я не знаком с вашим доменом, но предположим есть вариант использования, который сдвигает State от Quadrant на Field в другую. Как вы сказали,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);
    }
}

служба приложений сама по себе очень тонкая. Он не реализует логику домена; он только организует и задает этап для выполнения логики домена, которая включает доступ к репозиторию. Все зависящие от кода домена, такие как уровень представления или Служба, будут вызывать домен функциональность через эту службу приложений.

репозиторий может быть реализован различными способами. Это может быть с ORM, таким как NHibernate, в этом случае отслеживание изменений встроено, и обычным подходом является фиксация всех изменений вместо вызова явного обновления. NHibernate предоставляет единица работы а также позволяет изменения в нескольких сущностях могут быть зафиксированы как один.

в вашем случае, как вы заявили, нет отслеживания изменений таким образом, требуется явный вызов обновления, и это зависит от реализации репозитория для обработки этого. При использовании SQL Server в качестве базы данных Update метод в репозитории может просто отправить все свойства Field в хранимую процедуру, которая будет обновлять таблицы по мере необходимости.


агрегатный корень (AR) обновляется somwehere. Используя архитектуру, управляемую сообщениями, это где-то является обработчиком команд, но, скажем, для общего назначения это служба. Служба получает AR из репозитория, вызывает соответствующие методы, а затем сохраняет AR обратно в репозиторий.

AR не знает о репозитории, это не его забота. Затем репозиторий сохраняет все AR-модификации как единицу работы (то есть все или ничего). Как РЕПО это делает, ну, это зависит от того, как вы решили свою стратегию настойчивости.

Если вы используете источник событий, то AR генерирует события, и РЕПО будет использовать эти события для сохранения состояния AR. Если вы возьмете более распространенный подход, то AR должен иметь данные состояния где-то, возможно, как свойство. Это называется memento pattern. Репозиторий сохраняет эти данные в одной фиксации.

Bu одно несомненно: никогда не думайте о деталях персистентности, когда имеете дело с доменом объект. То есть не соединяйте домен с ORM или с каким-то конкретным материалом db.


" код приложения " должен вызывать репозиторий. Как размещается код приложения-это инфраструктурная проблема. Некоторые примеры размещения кода приложения-служба WCF, приложение Winforms/WPF или веб-сервер.

реализация репозитория отвечает за отслеживание изменений в aggregate root и его дочерних сущностях, а также сохранение их обратно в БД.

вот пример:

домен Проект

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

Если вам нужно транзакционировать изменения в несколько совокупных корней, чтобы изменения были сделаны на основе всего или ничего, тогда вы должны посмотреть в шаблон единицы работы.

надеюсь, это поможет прояснить вещи!


мое решение-совокупный корень вызовет некоторые события для обработчиков событий снаружи. Эти обработчики событий будут вызывать repository для обновления базы данных. Вам также понадобится 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);
    }
}