repository - 事件源聚合根是否应该有权访问事件源存储库?

标签 repository domain-driven-design cqrs

我正在处理 event-sourced CQRS 实现,在应用/领域层使用 DDD。我有一个看起来像这样的对象模型:

public class Person : AggregateRootBase
{
    private Guid? _bookingId;

    public Person(Identification identification)
    {
        Apply(new PersonCreatedEvent(identification));
    }

    public Booking CreateBooking() {
        // Enforce Person invariants
        var booking = new Booking();
        Apply(new PersonBookedEvent(booking.Id));
        return booking;
    }

    public void Release() {
        // Enforce Person invariants
        // Should we load the booking here from the aggregate repository?
        // We need to ensure that booking is released as well.
        var booking = BookingRepository.Load(_bookingId);
        booking.Release();
        Apply(new PersonReleasedEvent(_bookingId));
    }

    [EventHandler]
    public void Handle(PersonBookedEvent @event) { _bookingId = @event.BookingId; }

    [EventHandler]
    public void Handle(PersonReleasedEvent @event) { _bookingId = null; }
}

public class Booking : AggregateRootBase
{
    private DateTime _bookingDate;
    private DateTime? _releaseDate;

    public Booking()
    {
        //Enforce invariants
        Apply(new BookingCreatedEvent());
    }

    public void Release() 
    {
        //Enforce invariants
        Apply(new BookingReleasedEvent());
    }

    [EventHandler]
    public void Handle(BookingCreatedEvent @event) { _bookingDate = SystemTime.Now(); }
    [EventHandler]
    public void Handle(BookingReleasedEvent @event) { _releaseDate = SystemTime.Now(); }
    // Some other business activities unrelated to a person
}

到目前为止,根据我对 DDD 的理解,Person 和 Booking 都是单独的聚合根,原因有两个:
  • 有时业务组件会从数据库中单独提取 Booking 对象。 (即,已被释放的人员由于信息不正确而修改了先前的预订)。
  • 每当需要更新 Booking 时,Person 和 Booking 之间不应有锁定争用。

  • 另一项业务要求是,一个人的 Booking 一次不能超过一次。因此,我担心在读取端查询查询数据库,因为那里可能存在一些不一致(由于使用 CQRS 并具有最终一致的读取数据库)。

    是否应该允许聚合根通过对象的 id 查询事件源后备存储(根据需要延迟加载它们)?还有其他更有意义的实现途径吗?

    最佳答案

    首先,你真的真的需要事件溯源吗?对我来说看起来很简单。事件溯源既有优点也有缺点。虽然它为您提供免费的审计跟踪并使您的域模型更具表现力,但它使解决方案复杂化。

    好的,我假设此时您已经考虑了您的决定,并且您决定继续使用事件溯源。我认为您缺少消息传递作为聚合之间通信手段的概念。它在 Pat Helland's paper 中有最好的描述(顺便说一句,不是关于 DDD 或事件溯源,而是关于可扩展性)。

    这个想法是聚合可以相互发送消息以强制执行某些行为。聚合之间不能有同步(也称为方法调用)交互,因为这会引入一致性问题。

    在您的示例中,Person AR 将向 Booking AR 发送 Reserve 消息。此消息将以某种异步且可靠的方式传输。预订 AR 会处理这个消息,如果它已经被另一个人预订了,它会回复 ReservationRejected 消息。否则,它将发送 ReservationConfirmed。这些消息必须由 Person AR 处理。也许,他们会生成另一个事件,该事件将被转换为发送给客户的电子邮件或类似的东西。

    不需要在模型中获取查询数据。只是发消息。如果你想要一个例子,你可以下载Ncqrs的“消息”分支的源代码。项目并查看 ScenarioTest 类。它使用 Blue Book 中的 Cargo 和 HandlingEvent 示例演示了 AR 之间的消息传递。

    这回答了你的问题了吗?

    关于repository - 事件源聚合根是否应该有权访问事件源存储库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2906370/

    相关文章:

    oop - DDD - 补充骨料根的水分?

    image - 如何从图像生成 Dockerfile?

    domain-driven-design - DDD与企业架构的共识

    git - 在气隙环境中使用 docker 的最佳实践

    c# - 没有数据库的单元测试 : Linq to SQL

    domain-driven-design - 在事件溯源环境中对聚合根及其相关实体进行再水化的最佳方法是什么

    publish-subscribe - CQRS + 事件溯源 : (is it correct that) Commands are generally communicated point-to-point, 而领域事件通过发布/订阅进行通信?

    java - 在 Axon 中投影 @AggregateVersion

    maven-2 - Maven 存储库配置

    macos - 如何使用 homebrew 获取 avidemux