我將用戶建模爲聚合根,用戶由標識符值對象以及電子郵件值對象組成。兩個值對象都可以唯一標識一個用戶,但是電子郵件被允許改變,而標識符不能。DDD - 存儲庫可以通過標識符以外的其他東西獲取聚合嗎?
在我看到的大多數DDD示例中,聚合根的存儲庫只能通過標識符獲取。添加另一種通過電子郵件獲取存儲庫的方法是否正確?我的模型很糟糕嗎?
我將用戶建模爲聚合根,用戶由標識符值對象以及電子郵件值對象組成。兩個值對象都可以唯一標識一個用戶,但是電子郵件被允許改變,而標識符不能。DDD - 存儲庫可以通過標識符以外的其他東西獲取聚合嗎?
在我看到的大多數DDD示例中,聚合根的存儲庫只能通過標識符獲取。添加另一種通過電子郵件獲取存儲庫的方法是否正確?我的模型很糟糕嗎?
我會把這個功能放到特定於你的用戶對象的服務/業務層。並非每個對象都有一個電子郵件標識符。這看起來更像業務邏輯而不是倉庫的責任。我相信你已經知道這一點,但here是我正在談論的很好的解釋。
我不建議這一點,但你可以有一個具體的實施信息庫的暴露a GetByEmail(string emailAddress)
方法的用戶,但我還是喜歡的服務理念。
我想說的是,對於存儲庫來說,通過除身份之外的其他東西來獲取聚合的方法是合適的。但是,要注意一些細節。
許多存儲庫示例僅通過ID檢索的原因是基於以下觀察結果:存儲庫與聚合結構相結合無法滿足所有查詢要求。例如,如果您有一個查詢從集合中調用某些字段以及引用集合和某些摘要數據的某些字段,則相應的集合類不能用於表示此數據。相反,需要專用的read-model。因此,查詢職責與存儲庫分離。這有幾個優點(查詢可以由專門的非標準化商店提供)並且它是CQRS的主要範例。在這種類型的體系結構中,只有在需要執行某些行爲時,才能通過存儲庫檢索域類。所有隻讀用例均由讀取模型提供。
我認爲它適合存儲庫有一個GetByEmail方法的原因是基於YAGNI和戰鬥的複雜性。你可以讓你的應用隨着需求的變化和發展而發展。您不需要跳到CQRS並立即分開讀/寫存儲。您可以從一個也恰好具有查詢方法的存儲庫開始。唯一要記住的是,當你需要調用這些實體的某些行爲時,你應該嘗試通過ID檢索實體。
我同意eulerfx已經回答了:
你需要問自己,爲什麼你需要獲得使用除ID以外的東西 的AR。
我認爲這將是相當明顯的,你不有ID,但你做有一些其他的唯一標識符,如電子郵件地址。
如果您使用CQRS,您需要首先確定數據對於域還是僅對查詢存儲很重要。如果你要求數據100%一致,那麼它會稍微改變一些事情。例如,如果您要檢查是否存在電子郵件地址以滿足唯一約束條件,那麼您將需要100%的一致性。如果查詢的數據在任何時候過時,您可能會遇到問題。
請記住,一個庫代表的是一種集合。因此,如果您不需要真正在AR上進行操作(命令端),但是您已經決定在哪裏使用您的域,那麼您可以隨時在存儲庫上輸入ContainsEMailAddress
;否則,因爲您的域數據存儲(OLTP類型存儲)是100%一致的,而您的查詢存儲(OLAP類型存儲)最終可能只會最終一致,所以您也可以爲您的域數據存儲設置查詢端,就像典型的CQRS查詢商店。
難道是正確的補充,通過電子郵件獲取到存儲庫的另一種方法? - 我不會那樣做。在我看來,存儲庫應該只有通過id,save和delete來獲取的方法。
我寧願問,爲什麼你沒有用戶ID在你想獲取用戶和呼叫的域方法就可以了命令處理程序。我不知道你到底在做什麼,但是對於登錄/註冊場景,我會跟着做。當用戶登錄時,他會傳遞一個電子郵件地址和一個密碼,然後執行查詢來驗證用戶身份 - 這不會使用域或存儲庫(僅用於命令),但會使用某些查詢實現, UserDto將包含用戶ID,從這一點你有用戶ID。下一個場景是註冊。命令處理程序創建一個新的用戶將創建一個新用戶的實體,那麼用戶需要登錄。
在我見過DDD的大多數例子中,以總 根的倉庫只能由標識符獲取。
我很想知道你看過的例子。根據DDD definition,存儲庫是
一種封裝存儲機構,檢索,和搜索行爲 ,其模仿對象的集合。
搜索顯然包括通過各種標準獲取根或根的集合,而不僅僅是它們的ID。
庫是GetCustomerByEmail()
,GetCustomersOver18()
,GetCustomersByCountry(...)
等的理想場所。
這意味着你可以不通過倉庫到命令處理程序在一個通用的方法(IRepository),但它需要一個專門的版本IUserRepository。所以你需要記住哪個實體有專門的存儲庫,哪個實體有通用的。最近我在看這個,發現這個關於'finder pattern'的博客,這可能是一個更好的通用庫存儲搜索解決方案:http://russelleast.wordpress.com/2008/09/20/implementing-the-repository-and- finder-patterns/ –
xhafan
我看不出它是如何更通用的解決方案。 'IEntityFinder'實現,因爲他們在博客文章中描述了還含有特定的方法('ByLoginName()','ByToken()'...)沒有在接口級別出現。所以只知道「EntityRepository 」的命令處理程序無論如何都不會知道這些方法。 –
guillaume31
在我看來,文章是關於「爲我們的存儲庫提供流暢的接口」,而不是將通用命令處理程序與通用存儲庫配對。實際上,我不認爲存儲庫應該系統地公開一個通用接口。更多關於此這裏:http://codebetter.com/gregyoung/2009/01/16/ddd-the-generic-repository/ – guillaume31