Чтобы отключить профиль, связанный с пользователем, мы обычно
User.RemoveProfile(ProfileId)
.Profile.Disable()
.Profile.Disable()
мы вызываем событие ProfileDisabled
.В настоящее время события хранятся внутри каждой сущности. Когда мы сохраняем пользователей в базе данных, мы проходим события под пользователем, а НЕ под всеми связанными профилями. В результате мы не отправляем события профиля, и они теряются.
Для справки это код, который мы используем для отправки события:
public abstract class Repository
{
private readonly IMediator _mediator;
protected Repository(IMediator mediator) => _mediator = mediator;
// Future: Use EventStore for audit
/* Bug: Disable profile raises an event stored at the profile level. When user gets updated only
user events are dispatched. Profile events are lost... */
protected async Task DispatchEventsAsync(Entity entity, CancellationToken token)
{
Ensure.Any.IsNotNull(entity, nameof(entity));
await Task.WhenAll(entity.Events.Select(e => _mediator.Publish(e, token)));
entity.SuppressEvents();
}
}
Где Entity
:
public interface IEntity { }
public abstract class Entity : IEntity
{
private readonly List<DomainEvent> _events = new List<DomainEvent>();
[NotMapped]
public IReadOnlyList<DomainEvent> Events => _events.AsReadOnly();
public bool HasEvents => _events.Any();
protected void Emit(DomainEvent eventItem)
{
if (eventItem != null && !_events.Contains(eventItem))
_events.Add(eventItem);
}
public void SuppressEvents() => _events.Clear();
}
Как видите, Entity НЕ знает о связанных объектах. Нет возможности получить доступ к связанным событиям.
Как бы справиться с этим делом? Означает ли это, что только Aggregate Root может вызывать события?
Спасибо Себ
Идея обычно заключается в том, что все взаимодействие должно происходить через AR, так что, возможно, это правильный путь. Кроме того, если вы предпочитаете объекты-значения сущностям в своем AR, AR в любом случае должен будет позаботиться о событии (ах). Я бы согласился с этим планом :)
Действительно. Хорошее решение. Другая альтернатива, которую мы нашли, заключается в использовании EF Core для перечисления всех добавленных / измененных / удаленных сущностей, просмотра их в цикле и отправки связанных событий.
Я предполагаю, что у вас есть агрегат с двумя сущностями: Пользователь и Профиль. А Пользователь - это AR.
События возникают, когда вы выполняете операцию с агрегатом, поэтому вы должны хранить их в AR.
В вашем случае операция - «user.removeProfile (profileId)», поэтому AR должен вызвать событие «ProfileRemovedFromUser» или что-то в этом роде.
ПРИМЕЧАНИЕ. Ваш UL неоднозначен, поскольку вы используете слова «удалить» и «отключить» для одного и того же. Вы должны использовать только одно слово.
Я не специалист по C#, но не могли бы вы просто перегрузить метод
public IReadOnlyList<DomainEvent> Events => _events.AsReadOnly();
? в классеUser
он должен возвращать свои события и события из вложенных профилей