事件来源 - 我们应该只保存对象或所有对象的值的事件存储吗?

时间:2016-02-24 17:24:36

标签: c# cqrs

我正在尝试用cqrs了解事件来源。据我所知 - 命令处理程序保存对关系数据库的更改并抛出应该保存在nosql数据库中的事件。我有Notes类(这是我在数据库中的表):

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; }
}

如果某人仅修改单个音符的标题,那么我应该创建具有属性的事件:Id和Title,或者可能包含类Notes的所有属性?因为现在我创建了包含所有属性的事件 - 我不会检查哪个属性已更改:

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);
        }
    }
}

我这样做是否正确并且理解是否正确?

1 个答案:

答案 0 :(得分:1)

  

我正在尝试用cqrs来理解事件采购。

     

据我所知 - 命令处理程序保存对关系数据库的更改并抛出应保存在nosql数据库中的事件。

没有。想想在不同时间发生的两种不同行为。

首先:命令处理程序保存事件(通常会有多个事件)。这是事件采购部分 - 事件的顺序是记录系统;事件用于为下一个 write 重新实现实体,因此事件存储是CQRS的 C 方面的一部分。

为此部分使用nosql数据库是一个实现细节;使用关系数据库来存储事件是相当常见的(例如:http://blog.oasisdigital.com/2015/cqrs-linear-event-store/)。

在完成对记录系统的写入之后,该数据(事件流)用于在读取模型中创建新投影。这可以有你喜欢的任何表示,但理想情况下,最适合你的阅读模型。换句话说,您可以在关系数据库中创建数据的表示形式;或者你可以运行一堆查询并将结果缓存在一个nosql商店中,或者.... CQRS的目的是将写入问题与读取问题分开 - 一旦你完成了,你可以单独调整每一方面

请注意,如果您从一个正在从对象存储库读取和写入的写入模型开始,将该模型扩展到调度事件(正如您在此处所做的那样)是一个合理的中间步骤。

但是如果你从头开始,你就不会在写模型中保存Note的当前状态(没有对象存储),只是将音符置于当前状态的事件序列。

  

如果有人只修改单个标题的标题,那么我应该创建具有属性的事件:Id和Title,或者可能包含类Notes的所有属性?

最佳做法是描述变化。

通常使用更细粒度的事件来完成。您可以使用EntityChanged,枚举已更改的字段(在大多数情况下,包括实体ID)。在CRUD解决方案中,有时候这一切都是有意义的。

但是,如果您正在为业务领域建模,通常会有一些上下文 - 这些变化的动机。完全充实的事件模型可能有多个事件描述对同一组字段的更改(考虑更正客户的邮件地址与跟踪客户已重新定位的用例)。

关键是如果写模型可以描述更改背后的含义,那么读模型不需要尝试从事件中包含的通用数据中猜测它。

发现该意图通常意味着在命令中捕获更多语义信息(在将其发送到写入模型之前)。换句话说,EditNoteCommand本身是模糊的,并且可以重命名事件以更明确地表达感兴趣的不同类型的编辑。