Skip to content

Migrer vers le Event Sourcing, partie 5: persister à l’aide des événements

by Julien on octobre 24th, 2010

An english version of this post is available here.

Vue d’ensemble

L’étape précédente a introduit un problème. Nous avons maintenant 2 modèles représentant nos aggrégats: la base de données relationnelle, et nos événements. Pouvons nous être sûr que ces deux modèles sont cohérents? Non, car il n’y a aucun lien entre la base de données maintenue par NHibernate et nos événements:

C’est pourtant critique, car si nous voulons migrer au event sourcing, nous voulons nous assurer que les événements que nous générons reflètent bien le contenu de la base de données. La solution est de simplement utiliser nos événements pour persister les changements dans la base de données:

C’est l’objet de ce billet.

Avantages

Cohérence

Les événements sont maintenant la source des changements d’état dans nos aggrégats et dans la base de données.

Performance

Nous n’avons plus besoin de laisser NHibernate calculer les changements dans la session. En effet, le flush de session NHibernate est coûteux: NHibernate doit comparer l’état de chaque entité avec son état original afin de calculer les requêtes SQL nécessaires à la persistance des entités.

En utilisant les handlers d’événements, nous n’avons plus besoin de flusher la session NHibernate, car les événements décrivent déjà les changements d’état. Nous exécutons donc simplement des requêtes SQL spécifiques à chaque événement.

Implémentation

Ce qui a changé

Les handlers d’événements de persistance ont leur propre projet:

Unité de travail

Le premier élément de ce changement est le repository. Celui ci doit maintenant garder la liste des agrégats chargés et créés:

public T ById(Guid key)
{
    var resVal =  persistenceManager.CurrentSession.Get<T>(key);
    AddToContext(resVal);
    return resVal;
}

public void Add(T toAdd)
{
    AddToContext(toAdd);
}

private void AddToContext(T toAdd)
{
    HashSet<IAggregateRoot> aggregates = context[NHibernatePersistenceManager.AGGREGATE_KEY] as HashSet<IAggregateRoot>;

    if (aggregates == null)
    {
        aggregates = new HashSet<IAggregateRoot>();
        context[NHibernatePersistenceManager.AGGREGATE_KEY] = aggregates;
    }

    aggregates.Add(toAdd);
}

Il devient donc facile de persister les changements lors d’un commit, en appelant simplement les handlers:

public void Commit()
{
    var aggregates = context[AGGREGATE_KEY] as HashSet<IAggregateRoot>;

    if (aggregates != null && aggregates.Count > 0)
    {
        var session = EnsureOpened();

        using (var tx = session.Connection.BeginTransaction(IsolationLevel.ReadCommitted))
        {
            context[TRANSACTION_KEY] = tx;

            foreach (var ar in aggregates)
            {
                foreach (var evt in ar.UncommitedEvents)
                {
                    eventBus.Publish(evt);
                }
            }

            context[TRANSACTION_KEY] = null;
            tx.Commit();

            context[AGGREGATE_KEY] = null;
        }
    }
}

Handlers d’événements

L’implémentation des handlers est triviale. Par exemple:

public void Handle(StudentNameCorrectedEvent evt)
{
    persistenceManager.ExecuteNonQuery(
        "UPDATE [Student] SET firstName = @FirstName, lastName = @LastName WHERE Id = @Id",
        new
        {
            Id = evt.StudentId,
            FirstName = evt.FirstName,
            LastName = evt.LastName
        });
}

Démarrer l’application exemple

Les sources pour toute la série de billets sont disponible sur GitHub à http://github.com/jletroui/TransitioningToEventSourcing
.

Vous aurez simplement besoin de créer une base de données vide intitulée “DDDPart5″ dans SQLExpress avant de lancer l’application.

Liste des billets “migrer vers le Event Sourcing”:

From → Event Sourcing

Leave a Reply

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

Subscribe to this comment feed via RSS