Почему мое поле строки командного события извлекается как пустое

Я пишу свое первое тестовое приложение EventStore, я повторно гидратирую свой объект из потока, и хотя он правильно получает numberSold, заголовок имеет значение null, и я не понимаю, почему - команда при извлечении из потока имеет заголовок установлен как нулевой, но я уверен, что он пишется нормально.

Может ли свежий взгляд увидеть, что я делаю не так?

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

person morleyc    schedule 30.03.2013    source источник
comment
Я не вижу столбца полезной нагрузки для диагностики, так как все в шестнадцатеричном формате, я задал еще один вопрос об этом stackoverflow.com/questions/15723678/   -  person morleyc    schedule 31.03.2013
comment
Команда != Событие. Обратите внимание, что есть большая разница.   -  person Dennis Traub    schedule 31.03.2013


Ответы (1)


Хорошая работа для первого раза. В зависимости от того, как вы подключили поля, тот факт, что они имеют readonly, и отсутствие общедоступного конструктора без параметров, вероятно, вызовут проблемы с большинством механизмов сериализации, т.е. сделают их автоматическими свойствами.

Хотя мне обычно нравится защищать инварианты, ограничивая вещи, как у вас, важно сбалансировать это с тем фактом, что событие, как только оно произошло, полностью запекается, поэтому POCO с записываемыми свойствами не так безумен, как вы думаете.

Еще одна вещь, которую я бы сделал, это избавиться от идентификаторов событий.

(И присоединяйтесь к списку рассылки DDD-CQRS — там недавно обсуждалось понятие толстых событий — т. е. переформулирование материала, который можно почерпнуть из предыдущих событий [на основании того, что вы знаете, что обработчик событий должен реагировать на событие). событие], что, я согласен, является плохой идеей).

Я должен опубликовать свой AggregateBase - есть несколько тонкостей, которые вы правильно поняли, но я бы изменил много мелочей. Ткните меня через неделю, если я не сделал это раньше...

person Ruben Bartelink    schedule 30.03.2013
comment
репозиторий и агрегированный базовый справочный код будут очень признательны. имеет смысл в свойствах только для чтения, попробуем это сделать, когда вернемся в - person morleyc; 31.03.2013