【问题标题】:Why is my command event string field being retrieved as null为什么我的命令事件字符串字段被检索为空
【发布时间】:2020-10-27 18:46:34
【问题描述】:

我正在编写我的第一个 EventStore 测试应用程序,我正在从流中重新水化我的对象,虽然它正确获取了 numberSold,但标题为空,我不明白为什么 - 从流的标题设置为空,但我确信它写得很好。

一双新鲜的眼睛能看出我做错了什么吗?

private static void Main()
{
    using (store = WireupEventStore())
    {
        var newBook = new Book("my book", 0);
        newBook.ChangeBookName("renamed book");
        newBook.AdjustBooksSold(5);
        var idToRetrieveLater = newBook.bookId;

        var bookRepo = new BookRepository(store);
        bookRepo.Put(newBook);

        var bookReadBack = bookRepo.Get(idToRetrieveLater);
        // book name is set to null here, but count==5 is OK
}

图书课

public class Book
{ 
    public readonly Guid bookId;
    private int numberSold;
    private string title { get; set; }
    private List<object> eventsToCommit = new List<object>();

    public Book(string title, int sold)
    {
        this.bookId = Guid.NewGuid();
        this.title = title;
        this.numberSold = sold;
    }

    public Book(Guid id, IEnumerable<EventMessage> events)
    {
        this.bookId = id;
        foreach (var ev in events)
        {
            dynamic @eventToCall = ev.Body;
            Apply(@eventToCall);
        }
    }

    public void ChangeBookName(string name)
    {
        var nameChanged = new BookNameChanged(this.bookId, name);
        this.RaiseEvent(nameChanged);
    }

    public void AdjustBooksSold(int count)
    {
        var booksSold = new BookSold(this.bookId, count);
        this.RaiseEvent(booksSold);
    }

    private void Apply(BookNameChanged nameChanged)
    {
        this.title = nameChanged.title;
    }

    private void Apply(BookSold bookSold)
    {
        this.numberSold += bookSold.count;
    }

    protected void RaiseEvent(object eventToRaise)
    {
        dynamic @ev = eventToRaise;
        Apply(@ev);
        this.eventsToCommit.Add(eventToRaise);
    }

    public ICollection<object> GetEvents()
    {
        return this.eventsToCommit;
    }

    public void ResetEvents()
    {
        this.eventsToCommit = new List<object>();
    }
}

图书存储库

public class BookRepository
{
    IStoreEvents store;

    public BookRepository(IStoreEvents store)
    {
        this.store = store;
    }

    public void Put(Book book)
    {
        using (var stream = this.store.OpenStream(book.bookId, 0, int.MaxValue))
        {
            foreach (object o in book.GetEvents())
            {
                stream.Add(new EventMessage { Body = @o });
            }
            stream.CommitChanges(Guid.NewGuid());
            book.ResetEvents();
        }
    }

    public Book Get(Guid id)
    {
        using (var commits = this.store.OpenStream(id, 0, int.MaxValue))
        {
            var eventsToReply = commits.CommittedEvents;
            return new Book(id, eventsToReply);
        }
    }
}

命令

public class BookNameChanged
{
    public readonly Guid id;
    public readonly string title;

    public BookNameChanged(Guid id, string bookName)
    {
        this.id = id;
        this.title = bookName;
    }
}

public class BookSold
{
    public readonly Guid id;
    public readonly int count;

    public BookSold(Guid id, int count)
    {
        this.id = id;
        this.count = count;
    }
}

【问题讨论】:

  • 我看不到要诊断的有效载荷列,因为它全部是十六进制的,我已经提出了另一个关于这个stackoverflow.com/questions/15723678/…的问题
  • 命令 != 事件。请注意有很大的不同。

标签: event-sourcing neventstore


【解决方案1】:

第一次做的不错。根据您的连接方式,字段、它们具有 readonly 的事实以及缺少无参数的公共构造函数可能会导致大多数序列化机制出现问题 - 即使它们成为自动属性。

虽然我通常喜欢通过限制你所拥有的东西来保护不变量,但重要的是要平衡这一点与一个事件一旦发生就完全烘焙 - 所以具有可写属性的 POCO 并不像你想的那么疯狂想想。

我要做的另一件事是从事件中删除 id。

(并加入 DDD-CQRS 邮件列表 - 最近有一个讨论涉及到胖事件的概念 - 即重述可以从以前的事件中收集到的东西 [基于你知道事件处理程序需要什么对事件做出反应] 我同意这是一个坏主意)。

我必须发布我的AggregateBase - 你说对了一些微妙之处,但我会改变很多小事。如果我不早点做的话,一周后戳我......

【讨论】:

  • 存储库和聚合基本参考代码将不胜感激。对只读属性有意义会在返回时尝试
猜你喜欢
  • 1970-01-01
  • 2021-08-26
  • 1970-01-01
  • 2016-08-03
  • 2014-11-23
  • 2012-06-19
  • 1970-01-01
  • 2019-10-11
  • 1970-01-01
相关资源
最近更新 更多