문제

I'm working on an event-sourced CQRS implementation, using DDD in the application / domain layer. I have an object model that looks like this:

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
}

With my understanding of DDD so far, both Person and Booking are seperate aggregate roots for two reasons:

  1. There are times when business components will pull Booking objects separately from the database. (ie, a person that has been released has a previous booking modified due to incorrect information).
  2. There should not be locking contention between Person and Booking whenever a Booking needs to be updated.

One other business requirement is that a Booking can never occur for a Person more than once at a time. Due to this, I'm concerned about querying the query database on the read side as there could potentially be some inconsistency there (due to using CQRS and having an eventually consistent read database).

Should the aggregate roots be allowed to query the event-sourced backing store by id for objects (lazy-loading them as needed)? Are there any other avenues of implementation that would make more sense?

도움이 되었습니까?

해결책

First of all, do you really really need event sourcing in you case? It looks pretty simple to me. Event sourcing has both advantages and disadvantages. While it gives you a free audit trail and makes your domain model more expressive, it complicates the solution.

OK, I assume that at this point you thought over your decision and you are determined to stay with event sourcing. I think that you are missing the concept of messaging as a means of communication between aggregates. It is described best in Pat Helland's paper (which is, BTW, not about DDD or Event Sourcing, but about scalability).

The idea is aggregates can send messages to each other to force some behavior. There can be no synchronous (a.k.a method call) interaction between aggregates because this would introduce consistency problems.

In your example, a Person AR would send a Reserve message to a Booking AR. This message would be transported in some asynchronous and reliable way. Booking AR would handle this message and if it is already book by another person, it would reply with ReservationRejected message. Otherwise, it would send ReservationConfirmed. These messages would have to be handled by Person AR. Probably, they would generate yet another event which would be transformed into e-mail sent to customer or something like that.

There is no need of fetching query data in the model. Just messaging. If you want an example, you can download sources of "Messaging" branch of Ncqrs project and take a look at ScenarioTest class. It demonstrates messaging between ARs using Cargo and HandlingEvent sample from the Blue Book.

Does this answer your question?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top