Источник сорсинга событий развил различные стили за эти годы. Я мог бы разделить все эти на две большие категории:
- поток событий представляет одну сущность (совокупность в случае DDD)
- один (разделенный) поток событий для (подсистема)
Когда вы работаете с одним потоком на (подсистему), вы не можете повторно обработать сторону записи на лету, это физически невозможно из-за количества событий в этом потоке. Следовательно, для получения текущего состояния объекта вы должны полагаться на проецируемую сторону чтения. Как следствие, эта сторона чтения должна быть полностью согласованной.
При выборе источника событий с ароматом DDD в сообществе существует твердое согласие относительно того, как это должно быть сделано. Состояние агрегата (не только root, но и всего агрегата) восстанавливается командой перед вызовом модели домена. Вы всегда восстанавливаете, используя события. Когда снимок включен, снимки также сохраняются как события в совокупном потоке снимков, поэтому вы читаете последнее и все события из версии снимка.
Относительно вещи Apply
. Вам необходимо четко разделить функцию, которая добавляет новые события в список изменений (что вы собираетесь сохранить), и функции, которые изменяют агрегатное состояние при применении событий.
Первая функция - это функция с именем Apply
, а второй часто называют When
. Таким образом, вы вызываете функцию Apply
в своем агрегатном коде для создания списка изменений. Функция When
вызывается при восстановлении агрегатного состояния из событий при чтении потока, а также из функции Apply
.
Вы можете найти упрощенный c пример агрегата, полученного из событий в моей книге репо: https://github.com/alexeyzimarev/ddd-book/blob/master/chapter13/src/Marketplace.Ads.Domain/ClassifiedAds/ClassifiedAd.cs
Например:
public void Publish(UserId userId)
=> Apply(
new V1.ClassifiedAdPublished
{
Id = Id,
ApprovedBy = userId,
OwnerId = OwnerId,
PublishedAt = DateTimeOffset.Now
}
);
А для When
:
protected override void When(object @event)
{
switch (@event)
{
// more code here
case V1.ClassifiedAdPublished e:
ApprovedBy = UserId.FromGuid(e.ApprovedBy);
State = ClassifiedAdState.Active;
break;
// and more here
}
}