Skip to content

Transitioning to Event Sourcing, part 8: remove the domain database, go event sourced

by Julien on November 7th, 2011

Une version française de ce billet est disponible ici.

Overview

Finally we can terminate this refactoring. It is now trivial to use events to load our aggregates.

Benefits

Complete responsibility segregation

Loading our aggregates from the events allows us to “free” the persistent tables that are still performing the role of view model. This view model can now evolve independently, there is no more coupling to the transactional part of the application. And as always, less coupling means easier maintainability, and should speed up the addition of new features.

It also means that the transactional part of your application is no longer tied to a relational model. It is therefore much more easier to make it evolve. From the DDD point of view, it lowers the complexity barrier that push some teams to not re-factor their domain model as their understanding of the business evolve.

Implementation

What changed

What we need to change is the way we are loading our aggregates in the repository:

public T ById(Guid key)
{
    var events = eventStore.LoadEventHistory(key);

    var resVal = (T)constructor.Invoke(new Object[] { events });
    AddToContext(resVal);
    return resVal;
}

As you can see, we are first loading all the event history of the particular aggregate, and pass them to a new constructor on the aggregate.
Let’s look at the event store new method first:

public IEventInputStream LoadEventHistory(Guid aggregateId)
{
    using (var reader = persistenceManager.ExecuteQuery("SELECT [Version], [Data] FROM [Events] WHERE aggregate_id = @AggregateId ORDER BY [Version] ASC",
        new { AggregateId = aggregateId }))
    {
        var events = new List<IEvent>();
        var version = 0;

        while (reader.Read())
        {
            version = reader.GetInt32(0);
            var data = ((SqlDataReader)reader).GetSqlBinary(1).Value;
            events.AddRange(Deserialize(data));
        }

        return new SimpleEventInputStream(events, version, aggregateId);
    }
}

It is basically concatenating events of the commits of the given aggregate.

The new constructor in the aggregate root is even simpler. It is just calling the aggregate’s “Apply()” methods we already defined in part 4:

public AggregateRoot(IEventInputStream events) : this(events.AggregateId)
{
    Version = events.Version;

    foreach (var evt in events.Events)
    {
        ExecuteHandler(evt);
    }
}

private void ExecuteHandler<T>(T evt) where T : IEvent
{
    var handler = applyDelegates[this.GetType()][evt.GetType()] as Action<AggregateRoot, IEvent>;
    if (handler != null) handler(this, evt);
}

And that is it. You now have a fully working CQRS / Event Sourced application!

Running the sample

The sources for the entire series is available on GitHub at http://github.com/jletroui/TransitioningToEventSourcing
.

To run this sample, simply create a new “DDDPart6″ database in SQLExpress before launching it.
Last 3 steps of this series being very small and composable together, the single “part 6″ sample is actually covering parts 6 to 8.

Transitioning to Event Sourcing posts:

From → Event Sourcing

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS