我們想模擬一個倉庫應用程序。讓我們假設,我們確定了以下現實世界中的物體:如何使用DDD/CQRS/ES建模倉庫應用程序?
- 文章(存放在倉庫裏的東西)
- 調色板(其中文章都)
- 艙室(在機架在調色板的地方被存儲在)
有以下限制:
- 調色板是在恰好一個COM partment
- 甲隔室可以容納零個或一個調色板
對於開始,我們有一個操作:
- 移動(從它的當前隔室移動的調色板到另一個)。
當然這是非常簡單的。
這應該如何建模?
Stockitem可能是我認爲的價值對象。一種解決方案是將整個倉庫建模爲具有調色板和隔間實體的集合。在這種情況下,移動操作可以在其約束(不變量)的情況下實現而沒有任何問題。但是這種方法有明顯的缺點。此聚合的事件日誌將無限增長。由於彙總版本控制等原因,兩個移動操作不能並行執行。從DDD的角度來看,這感覺對我來說並不合適。
另一種方法是讓每個調色板和每個隔間自己的聚合。但是,如何實施移動操作呢?
問題1:誰加載引用的聚合?
我認爲它應該堅持調色板。調色板可以引用它所在的隔間(它是一個聚合體)。但是這個參考是如何實現的(CQRS/ES)?移動命令的Comandhandler顯然會從調色板存儲庫加載調色板聚集,並調用它的移動方法。誰加載參考隔間?誰加載隔間它應該移動到?我讀過聚合不應該訪問存儲庫。命令處理程序是否應該加載兩個隔離區?是否應該將隔間賦予移動方法作爲參數?或者,命令處理程序應將當前隔間設置爲調色板並將目標隔間設置爲參數?
問題2 & 3:約束和聚集體
怎麼樣的約束之間雙向關聯?要檢查目標隔間是否爲空,隔間需要知道存儲在其中的調色板。這將是一個應該避免的雙向關聯。而且由於它們是不同的集合,它們不能在同一個事務中更新。調色板是否觸發域事件以通知隔間它將移動到它?是否將其作爲撤銷行動的傳奇來實施?如果兩次衝突發生衝突,一次勝利,但是鬆動的調色板不能移回,因爲舊隔間在此期間被填滿了?
這一切對於我來說似乎都非常複雜,關於這個非常簡單的問題。
書中和例子看起來都很清楚。但如果我嘗試使用它,我似乎做錯了。
請問有人能指引我正確的方向嗎?
第二種解決方案的問題在於,您仍然無法強制執行'Compartment'不能保留多個'Palette',反之亦然,這取決於關係端。我經常想知道是否可以依靠DB約束來執行這些規則。例如,如果您在'Palette'上保存'compartmentId'並執行'palette.moveTo(隔間)',則可以確保調色板將只有一個隔間,但不是隔間只有一個調色板。依靠數據庫約束來執行該規則是很簡單的,並且可以保持強大的一致性。 – plalx
@plalx我認爲我更喜歡在代碼中明確地使用這個不變量,並在'Compartment'中強制執行它,這要歸功於其內部的調色板計數,或者如果它沒有它,則必須有人傳遞它(或'隔間'可以直接調用Repo來獲得它) – guillaume31
是的,我意識到這一點。所以你認爲最終一致性的「傳奇」解決方案將是正確的方式?問題1問題的另一部分是,誰加載了所需的聚合。我會稍微澄清一下這個問題。 –