アプリケーション/ドメインレイヤーでDDDを使用して、イベントソースのCQRS実装に取り組んでいます。次のようなオブジェクト モデルがあります。
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 の理解では、次の 2 つの理由から、Person と Booking の両方が別個の集約ルートです。
- ビジネス コンポーネントが Booking オブジェクトをデータベースから個別にプルする場合があります。(つまり、リリースされた人は、誤った情報のために変更された以前の予約を持っています)。
- Booking を更新する必要があるときはいつでも、Person と Booking の間でロックの競合があってはなりません。
もう 1 つのビジネス要件は、一度に 2 回以上、Person に対して予約が発生しないことです。このため、(CQRS を使用し、最終的に一貫性のある読み取りデータベースを使用するため) 潜在的に不整合が発生する可能性があるため、読み取り側でクエリ データベースをクエリすることを懸念しています。
集約ルートは、オブジェクトの ID によってイベント ソースのバッキング ストアにクエリを実行できるようにする必要があります (必要に応じて遅延読み込みします)。より理にかなった実装の他の手段はありますか?