Pan Zdrowie
Pan Zdrowie

Reputation: 347

Event sourcing - should we save to event store only changes in values of object or all object?

I am trying to understand event sourcing with cqrs. As I understand - command handler saves changes to relational database and throws event which should be save in nosql database. I have Notes class (that is my table in database):

public partial class Notes
{
    public System.Guid Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public System.DateTime CreatedDate { get; set; }
    public System.DateTime ModifiedDate { get; set; }
}

If somebody modify only Title of a single note then I should create event with properties: Id and Title or maybe with all properties of class Notes? Because now I create event with all properties - I don't check which property has changed:

public abstract class DomainEvent
{
    public Guid Id { get; set; }
    public DateTime CreatedDateEvent { get; set; }
}

// my event:
public class NoteChangedEvent : DomainEvent
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime ModifiedDate { get; set; }
}

// my command handler class:
public class EditNoteCommandHandler : ICommandHandler<EditNoteCommand>
{
    private readonly DbContext _context;
    private readonly IEventDispatcher _eventDispatcher;

    public EditNoteCommandHandler(DbContext context, IEventDispatcher eventDispatcher)
    {
        _context = context;
        _eventDispatcher = eventDispatcher;
    }

    public void Execute(EditNoteCommand command)
    {
        Notes note = _context.Notes.Find(command.Id);
        note.Title = command.Title;
        note.Content = command.Content;
        note.ModifiedDate = DateTime.Now;

        _context.SaveChanges(); // save to relational database

        // throw event:
        NoteChangedEvent noteChangedEvent = new NoteChangedEvent
        {
            Id = note.Id,
            Title = note.Title,
            Content = note.Content,
            ModifiedDate = note.ModifiedDate,
            CreatedDateEvent = DateTime.Now
        };

        _eventDispatcher.Dispatch(noteChangedEvent);
    }
}

// my dispatcher class:
public class EventDispatcher : IEventDispatcher
{
    public void Dispatch<TEvent>(TEvent @event) where TEvent : DomainEvent
    {
        foreach (IEventHandler<TEvent> handler in DependencyResolver.Current.GetServices<IEventHandler<TEvent>>())
        {
            handler.Handle(@event);
        }
    }
}

Am I doing that correct and understand that correct or not?

Upvotes: 3

Views: 2943

Answers (1)

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57257

I am trying to understand event sourcing with cqrs.

As I understand - command handler saves changes to relational database and throws event which should be save in nosql database.

No. Think two different actions, happening at different times.

First: the command handler saves the events (there will often be more than one). That's the event sourcing part - the sequence of events is the system of record; the events are used to rehydrate your entities for the next write, so the event store is part of the C side of CQRS.

Using a nosql database for this part is an implementation detail; it's fairly common to use a relational database to store the events (example: http://blog.oasisdigital.com/2015/cqrs-linear-event-store/ ).

After the write to the system of record is complete, that data (the event stream) is used to create new projections in the read model. That can have any representation you like, but ideally is whatever is most perfectly suited to your read model. In other words, you could create a representation of the data in a relational database; or you could run a bunch of queries and cache the results in a nosql store, or.... The point of CQRS is to separate the write concerns from the read concerns -- once you have done that, you can tune each side separately.

Mind you, if you are starting with a write model where you are reading and writing from an object store, extending that model to dispatch events (as you have done here) is a reasonable intermediate step to take.

But if you were starting from scratch, you would not ever save the current state of the Note in the write model (no object store), just the sequence of events that brought the note to the current state.

If somebody modify only Title of a single note then I should create event with properties: Id and Title or maybe with all properties of class Notes?

Best practices are to describe the change.

This is normally done with more finely grained events. You can get away with EntityChanged, enumerating the fields that have changed (in most cases, including the entity id). In CRUD solutions, sometimes that's all that makes sense.

But if you are modeling a business domain, there will usually be some context - some motivation for the change. A fully fleshed out event model might have more than one event describing changes to the same set of fields (consider the use cases of correcting the mailing address of a customer vs tracking that a customer has relocated).

The point being that if the write model can describe the meaning behind the change, the read model doesn't need to try to guess it from the generic data included in the event.

Discovering that intent often means capturing more semantic information in the command (before it is sent to the write model). In other words, EditNoteCommand itself is vague, and like the events can be renamed to more explicitly express the different kinds of edits that are of interest.

Upvotes: 2

Related Questions