發票的收件人必須是有效的聯繫人。
所以,你首先需要的是知道的 - 如果兩個實體是不同集合的一部分,你不能真正實現「將更改應用於僅是實體滿足規範這個實體」,因爲實體可能會在您評估規格的那一刻和執行寫入的那一刻之間發生變化。
換句話說 - 你只能得到最終跨越一個總界限的一致性。
聚集是其自身狀態的權限,但其他所有內容(例如命令消息的內容),它幾乎不得不接受某些外部權限已檢查數據。
有幾個方法,你可以採取這裏
1)您可以盲目地接受,在命令中指定的收件人是否有效。
2)您可以嘗試從接收來自某個外部授權機構(又名:某個其他彙總的讀取模型)的收件人的有效性,並將其從不可信來源提交併提交給域模型。
3)您可以盲目接受所述的命令,但將發票視爲暫時的,直到收件人的有效性得到確認。這意味着在發票上運行第二個命令來驗證收件人。
注 - 從視圖模型的角度來看,這些不同的命令是等價的,但在應用層,他們並不需要是 - 你可以限制訪問命令可信來源(不作它是公共api的一部分,需要僅可用於可信來源的授權等)。
方法#3是最微小的方法,因爲這兩個命令可以及時分開 - 您可以在CreateInvoice命令到達時立即接受,並以異步方式驗證收件人。
你會在哪裏把方法4),其中發票Microservice有它自己的聯繫人存儲,每當有一個ContactCreated或ContactDeleted事件時得到更新?那麼這兩個實體都是同一個服務和邊界的一部分。現在應該有可能讓事情保持一致,對嗎?
號你所做的相同服務的兩個實體的一部分,但問題是從來沒有,他們在不同的服務,但它們是在不同的聚集 - 這意味着我們可以同時更改實體狀態,這意味着我們無法確保它們立即同步。
如果你想立即保持一致性,你需要一個模型,以不同的方式繪製你的邊界。
例如,如果將發票實體建模爲聯繫人聚合的一部分,則聚合可以確保新發票需要有效收件人的不變量 - 域模型使用內存中狀態的副本來確認收件人爲,當我們加載時有效,並且寫入記錄簿確認記錄簿自加載發生以來未發生變化。
合計狀態的寫入是記錄簿中的比較和交換;如果某個併發進程已使接收方無效,則CAS操作將失敗。
當然,折衷是任何更改爲聯繫人彙總也會導致發票失敗;使用同一收件人同時編輯不同的發票將退出該窗口。
聚合是全部或沒有;他們不可分離。
現在,一個可能是您的發票集合中有一部分必須立即與收件人保持一致,另一部分最終一致或甚至不一致可接受。在這種情況下,您的目標是重構模型。
謝謝。這聽起來很有趣也很合理。讓我總結一下,看看我是否真的明白了你的觀點:如果用戶點擊'contact 42' *按鈕創建發票,用戶有責任注意'contact 42'存在。看起來很簡單。 **但是**如果用戶不關心該怎麼辦?然後它會創建一個包含無效收件人ID的發票。意思是:我的數據庫中有垃圾。它不好嗎?是的,但只限於可用磁盤空間。但它不會爲應用程序本身造成任何麻煩,因爲它只是一個孤立的數據。 –
@BenjaminM我已更新我的回答 –
好的。 (希望)唯一我仍然不明白的是:爲什麼*有效聯繫*業務規則,而不應該成爲發票的CommandHandler的一部分?這是不是有點類似於這個:發票有'currencyCode'屬性,它是一個字符串。在我看來,CommandHandler現在將驗證提供的'currencyCode'是否爲空,並且根據ISO 4217是有效的。是否它與*給定的收件人不是null並且根據我的Contacts Database *有效?也許我完全錯了。請賜教。 :) –