2010-05-25 62 views
5

我正在開發一個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的瞭解,到目前爲止,個人和預訂兩種原因有兩個單獨的總根源:

  1. 有些時候,業務組件會將預訂對象與數據庫分開。 (即,由於信息不正確,已發佈的人員之前的預訂已被修改)。
  2. 無論何時預訂需要更新,Person和Booking之間不應該存在鎖定爭用。

另一個業務需求是,一次預訂永遠不會發生一次。由於這一點,我擔心查詢查詢數據庫在讀取方面,因爲可能會有一些不一致(由於使用CQRS並具有最終一致的讀取數據庫)。

是否應該允許聚合根據對象(根據需要延遲加載它們)通過id的事件源後備存儲查詢?是否還有其他更有意義的實施途徑?

+0

「公衆人物(識別標識) { 應用(新PersonCreatedEvent(標識));} 」如果你正在構建從內存中的對象會發生什麼,你不是創建一個新的人,但你將發佈一個新的事件。我喜歡你定義事件處理程序的方式。所以知道一個對象的狀態只能在將一個命令應用到一個存儲庫時才能改變,也許你應該添加命令處理程序,除非你要完全基於事件,恕我直言並沒有多大意義。 – Marco 2013-08-12 14:25:36

+0

我無法弄清楚爲什麼你要處理一個你自己的倉庫應該發佈的事件? 「BookingCreatedEvent」 – Marco 2013-08-12 14:31:25

回答

10

首先,你真的需要事件採購嗎?這對我來說很簡單。事件採購既有優點也有缺點。雖然它爲您提供免費的審計跟蹤並使您的域模型更具表達力,但它使解決方案變得複雜。

好的,我認爲在這一點上,你認爲你的決定,你決定留在事件採購。我認爲你錯過了將消息傳遞作爲聚合之間通信方式的概念。它在Pat Helland's paper(即順便說一下,不是關於DDD或事件源,而是關於可伸縮性)中被描述得最好。

這個想法是聚合可以發送消息給對方強制一些行爲。聚合之間不能有同步(a.k.a方法調用)交互,因爲這會引起一致性問題。

在您的示例中,Person AR將向預訂AR發送預留消息。該消息將以一種異步可靠的方式傳輸。預訂AR將處理此消息,並且如果已經由另一個人預訂,它將使用ReservationRejected消息進行回覆。否則,它會發送ReservationConfirmed。這些消息必須由Person AR處理。可能他們會產生另一個事件,這個事件會被轉換成發送給客戶的電子郵件或類似的東西。

無需在模型中提取查詢數據。只是消息。如果你想要一個例子,你可以下載Ncqrs項目的「Messaging」分支的源代碼,並看看ScenarioTest類。它使用藍皮書中的Cargo和HandlingEvent示例演示AR之間的消息傳遞。

這是回答您的問題嗎?

+1

如果您強制進行同步處理,會遇到什麼樣的一致性問題?看起來這只是我的可擴展性問題,但我可能會錯過一些東西。 – 2010-06-01 13:24:58

+0

我假定存儲模型不支持存儲交叉聚合事務。如果它支持,那麼正常的方法調用就可以(至少就一致性而言)是正確的。 – 2010-06-02 11:21:50

+0

看過帕特赫蘭的論文後,我看到你來自哪裏。在這個特定的系統中,我並不關心近乎無限的可伸縮性(儘管如此,這將是一個不錯的問題)。作爲實現細節,我們使用MSMQ。我相信在我們的場景中2PC使用MSMQ是可以接受的。不過,我確實喜歡這個想法,並且給了我一些思考。 – 2010-06-03 04:26:39