代码之家  ›  专栏  ›  技术社区  ›  JD Courtoy

事件源聚合根是否可以访问事件源存储库?

  •  5
  • JD Courtoy  · 技术社区  · 15 年前

    我正在研究 event-sourced CQR实现,在应用程序/域层使用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的理解,个人和预订都是分开的,原因有两个:

    1. 有时业务组件将从数据库中单独提取预订对象。(即,由于信息不正确,已发布的人员已修改了以前的预订)。
    2. 每当需要更新预订时,人员和预订之间不应该存在锁定争用。

    另一个业务要求是,一个人每次不能预订超过一次。因此,我关心的是在读取端查询查询数据库,因为那里可能存在一些不一致性(由于使用了CQR并拥有最终一致的读取数据库)。

    是否应允许聚合根按ID查询对象的事件源备份存储区(根据需要延迟加载它们)?有没有其他更合理的实施途径?

    1 回复  |  直到 7 年前
        1
  •  10
  •   Marc Bachmann    7 年前

    首先,你真的需要事件源吗?我觉得很简单。活动采购既有优点也有缺点。虽然它为您提供了一个免费的审计跟踪,使您的域模型更具表现力,但它使解决方案复杂化。

    好的,我假设在这一点上,您考虑了您的决定,并且您决定继续参与活动采购。我认为您缺少了将消息传递作为聚合之间通信方式的概念。最好用 Pat Helland's paper (顺便说一句,这不是关于DDD或事件源,而是关于可扩展性)。

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

    在您的示例中,一个人ar将向预订ar发送预订消息。此消息将以某种异步和可靠的方式传输。预订AR将处理此消息,如果它已经被另一个人预订,它将以ReservationRejected消息回复。否则,它将发送已确认的预订。这些消息必须由ar人员处理。很可能,它们将生成另一个事件,该事件将转换为发送给客户的电子邮件或类似的事件。

    不需要在模型中提取查询数据。只是信息。如果需要示例,可以下载的“消息”分支的源 Ncqrs 计划并查看scenariotest类。它演示了ARS之间的消息传递,使用BlueBook中的Cargo和HandlingEvent示例。

    这能回答你的问题吗?