2017-09-06 57 views
1

給定一個訂單集合,它由Order和OrderItems組成。訂單是聚合根。放置訂單是唯一需要事務才能保證數據一致性的場景。或者至少有很多場景涉及改變數據的順序和orderItems,不需要交易。爲什麼聚合中的每個數據更改應該處於事務中?

在DDD之前,交易是在創建方法期間做出的決定。您通常會認爲此方法或行爲是否需要在事務中以保持一致性。

DDD建議爲聚合根暴露的每種可能行爲進行事務處理。這實際上可能導致更多的死鎖。

我想我不必在聚合根中實現每個數據更改行爲在事務中。

例如,如果您僅更改送貨詳細信息,爲什麼還需要交易。如果你只是刪除一個訂單項目,爲什麼你需要一個交易。所以對於Order.UpdateOrder和Order.DeleteOrderItem方法,我們不應該考慮事務。

我想念什麼?

回答

0

是的,我想你錯過了什麼。如果你正確地設計你的聚合,特別是如果你讓它們足夠小,那麼你不會有無意義的交易,至少不是很多。你的聚合應該是高度一致的,所以同時修改的屬性/狀態應該保持在同一個聚合中;這是一個聚合點,以保護對狀態的併發訪問。

如果你的聚合比他們應該大,那麼聚合force-field是太寬了而且沒有凝聚力的命令將被序列化爲空。

關於orders,不會有很多失敗的交易,因爲在同一時間添加order item和更改order shipping details的概率非常低。

無論如何,由於交易在任何情況下都不會發生死鎖,但可能發生失敗的交易。

+0

對於死鎖的可能性檢查這個職位。 https://stackoverflow.com/questions/34662578/in-domain-driven-design-why-would-you-use-an-aggregate-object-and-what-key-pr – Costa

+0

我說並非所有的行爲在根集合中需要在事務中。 我認爲在一致性問題是可能的時候我們應該考慮交易,並且應該基於分析行爲。 例如,如果您僅更改送貨細節,爲什麼您需要一個交易。如果您只刪除訂單商品,爲什麼需要交易。所以在Order.UpdateOrder和Order.DeleteOrderItem方法中,我們不應該考慮事務。 – Costa

+0

@Costa但是在這些情況下你需要事務處理,否則根據你的存儲庫實現它可能會變得混亂。請記住,聚合在處理命令之前/之前完全加載,應該沒有延遲加載。 –

0

在最純粹的形式存儲庫將有很少的方法:

public interface IAggregateRepository 
{ 
    AggregateRoot Get(Guid id); 
    void Save(AggregateRoot instance); 
} 

沒有用例之間沒有區別/在這種情況下的命令。您不一定知道是否需要交易。

另一個考慮因素是交易應該在集成/應用程序中處理。這進一步將事務處理從域交互中移除。

可能有應用程序需要了解特定用例並決定放棄某些命令的事務。但是,這可能是更值得的努力。

最後一點是,交易並不總是隻有什麼正在做的又談何別人在做什麼。

我會在謹慎的一方犯錯,而寧願使用交易。如果有一個特定的理由不使用交易,那麼這當然是一種選擇,但這似乎更適合讀取。

0

如果你有需要的地方在系統中更新只是一個航運細節,除了以下您可能有不同的聚合不同的界上下文核心DDD的做法,讓我們稱之爲ShippingRequest,它只有兩個字段,OrderIdShippingDetails ,並且最終可能映射到或不映射到相同的基礎表。然後這個聚合被事務隱含地覆蓋,因爲它只映射到一個表。

或者您可能不想關心所有這些有界的上下文,無處不在的語言和聚合,因爲DDD不值得實施,而且一些傳統的CRUD /交易腳本方法已經足夠。

問題也在於,DDD往往是時間解釋這樣的錯誤例子。聚合定義了一些一致性邊界,這是一些代表您業務規則的不變量。因此,如果Order作爲一個Aggregate,假設訂單被分配了一個不允許超過的最大允許總數。比這成爲一個自然聚合,因爲每當你想添加或刪除一個項目,整個聚合必須被檢索和更新爲一個單一的原子單位。

+0

即使沒有最大總數,OrderItem也不能在沒有Order的模型中生存,所以它不能聚合根,它必須是訂單彙總的一部分。 – Costa

+0

當然,如果它有屬性OrderId,您必須從構造函數中分配... –

+0

OrderID屬性不能添加到OrderItem,因爲它是針對OO封裝的。 – Costa

相關問題