2017-05-31 73 views
2

當前的項目需要我們在NoSQL數據庫(如mongoDB)中持久存在域對象。 在很多例子中(包括Eric Evans,Vaughn Vernon),域對象都被序列化並直接保存到mongoDB中。DDD - 如何在NoSql數據庫中存儲聚合

我們希望通過在域對象中沒有任何註釋來避免混合域層和持久性相關的信息。 此外,我們擔心未來通過更改域對象來破壞持久數據。

我們得出結論,我們需要在域對象和持久數據之間轉換某種DTO。

有沒有人遇到過這種情況的好解決方案?

+0

我使用反射來從mongo映射到PHP對象 –

+0

爲什麼不使用帶有xml映射的ORM? –

+0

@ConstantinGALBENU爲什麼在非關係數據的上下文中提到ORM,即對象關係映射?我很困惑。對象被序列化爲BSON並按原樣存儲在任何文檔數據庫中,包括MongoDb。 –

回答

1

是的。您的域模型應該對持久性無知。所以你需要一個DTO或我所謂的數據模型(除了領域模型和視圖模型)。在保存到數據庫之前,您的數據模型將映射到域模型。這種映射在插入和更新操作中很常見。對於只讀操作(報告等),您可以繞過從數據模型到域模型的映射。這將防止加載域模型的整個對象圖。這在CQRS體系結構模式中廣泛應用,其中讀取和寫入命令是分開的。

1

當前項目需要我們在NoSQL 數據庫(如mongoDB)中持久化域對象。在許多例子中(包括Eric Evans,Vaughn Vernon),域對象被序列化並直接保存到mongoDB 。

我可以確認你的是MongoDB是堅持DDD型號的不錯選擇。我在當前項目中使用MongoDB作爲Event store。即使您未使用Event sourcing,例如使用ODM(對象文檔映射器),也可以使用MongoDB:每個Aggregate實例(這適用於任何基於文檔的數據庫,不僅適用於MongoDB),並且存儲嵌套的entitiesvalue objects作爲嵌套文檔。

我們希望通過在域對象中沒有任何註釋來避免將域層與持久性相關的信息混合在一起。

您可以使用xml映射。

此外,我們關注的未來不斷變化的域對象破壞持久化數據。

爲此,您可以使用自定義遷移腳本。如果您使用Event sourcing,則有event versioning strategies

我們得出結論,我們需要在域對象和持久數據之間轉換某種DTO。

這是一個bad conclusion

如果您使用CQRS您將不需要DTO,因爲readmodels就足夠了。

0

您可以將您的域對象按原樣存儲在文檔數據庫中。 Vaughn Vernon發佈了一篇文章The Ideal Domain-Driven Design Aggregate Store?,其特色爲PostgreSQL新增(當時)JSONB文檔類存儲。

當然,您可能會遇到被聚合污染BsonX屬性的風險,您可能不希望這些屬性受到污染。您可以通過使用約定配置來避免這種情況,但您仍然需要考慮序列化,這可能會影響封裝級別。

此處的另一種模式是使用單獨的狀態對象,然後將其作爲聚合根(或常規實體)內的屬性保存。我不會稱之爲「DTO」,因爲這顯然是你的聚合狀態。你不是轉讓什麼。聚合中的方法可以改變狀態,或者更好的是,狀態將是不可變的值對象,當需要更改狀態時會產生新狀態。

在這種情況下,持久性只會關心狀態對象。對於狀態對象屬性有MongoDb屬性,您仍然可能不高興,這是合理的。然後,您將需要在持久性機制內具有相同的結構,以便您可以映射屬性一對一。

1

和你一樣,我希望業務對象不依賴於任何類型的特定存儲庫。我像這樣解決了這個問題:您的業務對象將其狀態對象和存儲庫函數定義爲接口。您的存儲庫實現可以創建一個實際的狀態對象,並使用構造函數將其注入業務對象。

這種方法有很多優點(例如具有特定用途的業務對象),但您可以通過這種方式輕鬆實現存儲庫的完全(雙向)獨立性。 Martin Fowler也在其他地方暗示了這種做法。

我實際上在我的Angular/TypeScript項目中使用了相同的模式。我的read-api調用返回的DTO對象也獲得了狀態對象,並且它們的屬性直接映射到狀態對象上。

這些DTO當它們來自客戶端(Angular)項目的api時,最終成爲無類型的javascript對象,然後作爲狀態對象注入到TypeScript對象中,再次注入構造函數並由getter和setter映射。它工作非常乾淨,維護性好。我在我的GitHub(niwra)帳戶(軟件管理存儲庫)上有一個例子,但如果有人感興趣,可以在這裏擴展。

MongoDB允許非常乾淨的單元測試版本庫實現,它返回強類型的聚合。我還沒有徹底解決的唯一事情就是告訴MongoDb關於子集合的狀態對象。目前這仍然是「靜態」,但我相信我會找到一些不錯的解決方案。