Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should an event-sourced aggregate root have access to the event sourcing repository?

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?

like image 953
JD Courtoy Avatar asked May 25 '10 16:05

JD Courtoy


People also ask

What is aggregate root event sourcing?

An Event Sourced Aggregate Root The aggregate root can be thought of as a number of functions that take value objects as arguments, execute the business logic and return events. Important: This means we never have any getters or expose the aggregate root's internal state in any way!

What is aggregate root CQRS?

Concretely, an aggregate will handle commands, apply events, and have a state model encapsulated within it that allows it to implement the required command validation, thus upholding the invariants (business rules) of the aggregate.

What is aggregate root in C#?

The Aggregate Root is the parent Entity to all other Entities and Value Objects within the Aggregate.


1 Answers

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?

like image 78
Szymon Pobiega Avatar answered Oct 15 '22 20:10

Szymon Pobiega