讓我們以一個簡單的「註冊帳號」的例子,這裏是流量:CQRS事件採購:驗證用戶名的唯一性
- 用戶訪問網站
- 點擊「註冊」按鈕,填寫表格,點擊「保存」按鈕
- MVC控制器:驗證用戶名的唯一性由ReadModel
- RegisterCommand閱讀:再次驗證用戶名的唯一性(這裏是問題)
當然,我們可以通過讀取MVC控制器中的ReadModel來驗證UserName的唯一性,以提高性能和用戶體驗。但是,我們仍然需要在RegisterCommand中再次驗證唯一性,顯然,我們不應該在Commands中訪問ReadModel。
如果我們不使用事件採購,我們可以查詢領域模型,所以這沒有問題。但是如果我們使用事件採購,我們無法查詢域模型,所以我們如何驗證RegisterCommand中的用戶名唯一性?
說明:用戶類具有Id屬性,UserName不是User類的關鍵屬性。使用事件採購時,我們只能通過Id獲取域對象。
BTW:在需求,如果輸入的用戶名已被使用,該網站應顯示錯誤消息「對不起,該用戶名XXX不可用」的訪問者。顯示一條消息,例如說,「我們正在創建您的帳戶,請等待,我們會在稍後通過電子郵件將註冊結果發送給您」,這是不能接受的。
任何想法?非常感謝!
[更新]
更復雜的例子:
要求:
下訂單時,系統應檢查客戶的訂貨歷史,如果他是一個有價值的客戶(如果客戶在過去一年每月至少訂購10份訂單,他很有價值),我們將訂單打九折。
實現:
我們創造PlaceOrderCommand,並在命令中,我們需要查詢訂貨歷史,看看如果客戶是有價值的。但我們怎麼做到這一點?我們不應該在命令中使用ReadModel!作爲Mikael said,我們可以在帳戶註冊示例中使用補償命令,但是如果我們也在此排序示例中使用補償命令,則它會太複雜,並且代碼可能太難以維護。
當我發現用戶名重複時,我應該在補償命令中做些什麼?發佈SignalR事件以通知客戶端用戶名不可用? (我沒有使用過SignalR,我想可能會有某種「事件?」) – 2012-02-29 09:21:32
很好的答案,謝謝!但是我對「域名服務」感到困惑,你是不是指「事件處理程序」?我認爲它與DDD中的「域服務」不一樣嗎? – 2012-02-29 13:00:14
我認爲我們稱之爲DDD中的應用服務,但我可能弄錯了,而域服務在DDDD/CQRS社區中是一個爭論的話題。除了你可能不需要狀態機或狀態機之外,它們與他們所說的Saga類似,你只需要一些能夠反應和反饋事件,執行數據查找和調度命令的東西,我稱之爲域服務。訂閱事件和發送命令,這在聚合根節點之間進行通信時非常有用 – 2012-02-29 14:48:35