【问题标题】:DDD Dispatch event of related entities相关实体的 DDD Dispatch 事件
【发布时间】:2018-10-31 09:35:58
【问题描述】:

要禁用与用户关联的个人资料,我们通常

  • 从数据库加载用户
  • 调用User.RemoveProfile(ProfileId)方法。
  • 在此方法中,我们将在列表中找到指定的配置文件,然后调用Profile.Disable()方法
  • Profile.Disable() 中,我们引发ProfileDisabled 事件。
  • 我们将用户 + 相关实体(在这种情况下为配置文件)完善到 DB。

当前事件存储在每个实体中。当我们将用户持久保存在数据库中时,我们会通过用户而不是所有相关配置文件下的事件。因此,我们不会调度配置文件事件,它们会丢失。

这是我们用来调度事件的代码供您参考:

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 不知道相关实体。这样就没有办法访问相关事件了。

如何处理这种情况?这是否意味着只有聚合根才能引发事件?

谢谢 赛博

【问题讨论】:

  • 我不是 C# 专家,但你不能重载 public IReadOnlyList&lt;DomainEvent&gt; Events =&gt; _events.AsReadOnly(); 方法吗?在User 类中,它应该返回自己的事件和嵌套配置文件中的事件
  • 这个想法通常是所有交互都应该通过 AR 进行,所以也许这就是要走的路。此外,如果您在 AR 中偏爱值对象而不是实体,那么 AR 无论如何都必须处理事件。我会按照这个计划去:)
  • 确实如此。很好的解决方案。我们发现的另一种选择是依靠 EF Core 列出所有添加/修改/删除的实体,遍历它们并调度相关事件

标签: .net .net-core event-handling domain-driven-design repository-pattern


【解决方案1】:

我猜你有一个包含两个实体的聚合:用户和个人资料。而用户就是 AR。

当您对聚合执行操作时会引发事件,因此您应该将它们与 AR 一起存储。

在您的情况下,操作是“user.removeProfile(profileId)”,因此 AR 应该引发事件“ProfileRemovedFromUser”或类似的事件。

注意:您的 UL 是模棱两可的,因为您使用 remove 和 disable 这两个词来表示同一件事。你应该只用一个词。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2021-10-20
    • 2021-10-31
    • 1970-01-01
    • 2015-10-26
    相关资源
    最近更新 更多