Должен ли агрегатный корень источника событий иметь доступ к хранилищу источников событий? - PullRequest
5 голосов
/ 25 мая 2010

Я работаю над реализацией CQRS с использованием событий, используя DDD на уровне приложений / доменов. У меня есть объектная модель, которая выглядит так:

public class Person : AggregateRootBase
{
    private Guid? _bookingId;

    public Person(Identification identification)
    {
        Apply(new PersonCreatedEvent(identification));
    }

    public Booking CreateBooking() {
        // Enforce Person invariants
        var booking = new Booking();
        Apply(new PersonBookedEvent(booking.Id));
        return booking;
    }

    public void Release() {
        // Enforce Person invariants
        // Should we load the booking here from the aggregate repository?
        // We need to ensure that booking is released as well.
        var booking = BookingRepository.Load(_bookingId);
        booking.Release();
        Apply(new PersonReleasedEvent(_bookingId));
    }

    [EventHandler]
    public void Handle(PersonBookedEvent @event) { _bookingId = @event.BookingId; }

    [EventHandler]
    public void Handle(PersonReleasedEvent @event) { _bookingId = null; }
}

public class Booking : AggregateRootBase
{
    private DateTime _bookingDate;
    private DateTime? _releaseDate;

    public Booking()
    {
        //Enforce invariants
        Apply(new BookingCreatedEvent());
    }

    public void Release() 
    {
        //Enforce invariants
        Apply(new BookingReleasedEvent());
    }

    [EventHandler]
    public void Handle(BookingCreatedEvent @event) { _bookingDate = SystemTime.Now(); }
    [EventHandler]
    public void Handle(BookingReleasedEvent @event) { _releaseDate = SystemTime.Now(); }
    // Some other business activities unrelated to a person
}

С моим пониманием DDD до сих пор и Person, и Booking являются отдельными совокупными корнями по двум причинам:

  1. Бывают моменты, когда бизнес-компоненты извлекают объекты бронирования отдельно от базы данных. (то есть, у освобожденного лица предыдущее бронирование было изменено из-за неверной информации).
  2. Не должно быть блокирующего разногласия между Лицом и Бронирование, когда требуется обновить Бронирование.

Еще одно деловое требование заключается в том, что бронирование для Лица никогда не может происходить более одного раза за раз. В связи с этим я обеспокоен запросом базы данных запросов на стороне чтения, поскольку там могут быть некоторые несоответствия (из-за использования CQRS и наличия в конечном итоге согласованной базы данных для чтения).

Следует ли разрешить агрегатным корням запрашивать хранилище резервных копий по событиям по идентификатору для объектов (загружая их по мере необходимости)? Есть ли другие способы реализации, которые могли бы иметь больше смысла?

1 Ответ

10 голосов
/ 31 мая 2010

Прежде всего, вам действительно нужен источник событий в вашем случае? Это выглядит довольно просто для меня. Источник событий имеет как преимущества, так и недостатки. Хотя это дает вам бесплатный контрольный журнал и делает модель вашего домена более выразительной, оно усложняет решение.

Хорошо, я предполагаю, что в этот момент вы продумали свое решение и решили остаться с источником событий. Я думаю, что вам не хватает концепции обмена сообщениями как средства связи между агрегатами. Это лучше всего описано в статье Пэт Хелланда (кстати, не о DDD или Event Sourcing, а о масштабируемости).

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

В вашем примере Person AR будет отправлять резервное сообщение в AR бронирования. Это сообщение будет передаваться асинхронным и надежным способом. Booking AR обработает это сообщение и, если оно уже забронировано другим лицом, ответит сообщением ReservationRejected. В противном случае он отправит ReservationConfirmed. Эти сообщения должны обрабатываться Person AR. Возможно, они сгенерируют еще одно событие, которое будет преобразовано в электронную почту, отправленную клиенту, или что-то в этом роде.

Нет необходимости извлекать данные запроса в модели. Просто обмен сообщениями. Если вам нужен пример, вы можете скачать исходные тексты ветки «Сообщения» проекта Ncqrs и взглянуть на класс ScenarioTest. Он демонстрирует обмен сообщениями между AR с использованием образца Cargo и HandlingEvent из Синей книги.

Это отвечает на ваш вопрос?

...