2010-08-09 80 views
10

我開始考慮跟蹤斷開應用程序中複雜對象圖的更改。我已經找到了幾種解決方案,但我想知道是否有最佳做法或者您使用哪種解決方案,爲什麼?我通過了同樣的問題MSDN forum,但我只收到單一的答案。我想有更多的答案來學習其他開發人員的經驗。跟蹤複雜對象圖中的更改

此問題與.NET有關,因此對於實現細節的答案我更喜歡與.NET世界相關的答案,但我認爲這與其他平臺上的答案相同。

在我的案件的理論問題在多層架構中定義的(不一定是n層的時刻),如下所示:使用ORM庫來應對持久性(ORM工具沒有的

  • 層目前的問題,但它最有可能是實體框架4.0或NHibernate)。
  • 表示域對象的純類(持久性無知= POCO,相當於Java世界中的POJO)的集合。存儲庫保留這些類並將其作爲查詢結果返回。
  • 一組使用域實體的域服務。
  • 門面層定義業務邏輯的網關。它在內部使用存儲庫,域服務和域對象。域對象不公開 - 每個外觀方法使用一組專用的數據傳輸對象作爲參數和返回值。每個Facade方法負責將域實體轉換爲DTO,反之亦然。
  • 使用外觀層和DTO的現代Web應用程序 - 我稱之爲斷開連接的應用程序。通常,設計將來可能會發生變化,因此Facade層將被Web服務層包裝,並且Web應用程序將使用該服務=>轉換到3層(Web,業務邏輯,數據庫)。

現在假設其中一個域對象是具有訂單明細(行)和相關訂單的訂單。當客戶請求訂單進行訂單管理時,它可以修改訂單,添加,刪除或修改任何訂單明細以及添加或刪除相關訂單。所有這些修改都是在Web瀏覽器中的數據完成的 - javascript和AJAX。因此,當客戶端按下保存按鈕時,所有更改都會以單次鏡頭提供。問題是如何處理這些變化?存儲庫和ORM工具需要知道修改,插入或刪除了哪些實體和關係。

  1. 商店DTO的初始狀態隱藏字段(在最壞的情況下,以會話):我有兩個「最佳」的解決方案結束。當接收到保存更改的請求時,根據收到的數據創建新的DTO,並根據持久數據創建第二個DTO。合併這兩個並跟蹤更改。將合併的DTO發送到外觀層,並使用收到的有關更改的信息正確設置實體圖。這需要在域對象中進行一些手動更改跟蹤,以便可以從頭開始設置更改信息,之後再將其傳遞到存儲庫 - 這是我不太滿意的一點。

  2. 不要跟蹤DTO的變化。當在Facade層接收修改後的數據時,創建修改的實體並從存儲庫加載實際狀態(通常是對數據庫的附加查詢 - 這是我不太滿意的一點) - 合併這兩個實體並通過ORM工具提供的實體代理自動跟蹤更改(實體框架4.0和NHibernate允許這個)。併發處理需要特別小心,因爲實際狀態不一定是初始狀態。

您對此有何看法?你有什麼建議?

我知道這些挑戰中的一些可以通過在某些應用層上使用緩存來避免,但這是我目前不想使用的。

我對這個話題的興趣更加深入。例如,假設應用程序轉到3層架構,並且客戶端(Web應用程序)不會用.NET編寫= DTO類不能重用。跟蹤DTO上的更改將變得更加困難,因爲它需要其他開發團隊在他們的開發工具中正確實施跟蹤機制。

我相信這些問題必須在大量的應用程序中解決,請分享你的經驗。

回答

3

這是關於責任。

(我不確定這是否是你之後的答案 - 讓我知道是否它不是我可以更新它)。因此,我們在系統中有多個層次 - 每個層次都負責不同的任務:數據訪問,UI,業務邏輯等。當我們以這種方式構建系統時,我們(除其他之外)試圖使未來通過讓每個組件負責一項任務來輕鬆更改 - 因此它可以專注於這一項任務並做得很好。隨着時間的推移和改變,它也使修改系統變得更加容易。

在考慮DTO時需要記住類似的想法 - 「如何跟蹤變化?」例如。以下是我的方法:BL負責管理規則和邏輯;考慮到網絡的無狀態特性(這是我完成大部分工作的地方),我只是沒有跟蹤對象的狀態並且明確地尋找變化。如果用戶正在傳回數據(將被保存/更新),我將把整個過程傳遞回去,而不必關心已經發生了什麼變化。

一方面,這可能看起來效率不高,但由於數據量並不龐大,所以不是問題;從另一方面來說,由於流程簡單得多,「移動部件」較少可能出錯。

我如何傳回數據? -

  • 我使用DTO的(或者也許POCO的會更準確);當我在BL和DAL之間交換數據時(通過接口/ DI),數據作爲DTO(或它們的集合)交換。具體來說,我使用一個結構爲單個實例和這些結構的集合爲多個。

  • DTO的定義在一個很少依賴的通用類中。

  • 我故意嘗試限制DTO創建特定對象(如「訂單」)的數量 - 但同時如果有充足的理由,我會創建新的。通常情況下,我會有一個「胖」的DTO,其中包含該對象的大部分/所有可用數據,我也可能有一個精心設計用於集合(用於列表等)的精簡版DTO。在這兩種情況下,這些DTO都是純粹的,用於返回「閱讀」信息。你必須記住責任 - 當BL要求數據時,通常不會嘗試同時寫回數據;所以DTO是「只讀」的事實更多的是符合乾淨的界面和架構而不是業務規則。

  • 我總是爲插入和更新定義單獨的DTO - 即使它們共享完全相同的字段。這樣可能發生的最糟糕的情況就是複製一些trival代碼 - 而不是依靠和多個重用案例來解決問題。

最後 - 不要混淆DAL如何與UI如何工作;讓ORM做他們的事情,僅僅因爲他們以一種給定的方式存儲數據並不意味着它是唯一的方法。

最重要的事情是你的層間指定有意義的接口。

管理什麼是BL的工作;讓用戶界面以最適合你的用戶的方式工作,讓BL瞭解它是如何處理這個問題的,DAL(通過你的漂亮的乾淨界面DI)只是按照它的要求進行操作。

+1

你好,非常感謝你的回答。我喜歡。它與我的架構非常接近,除了在我的情況下,我在BL和DAL之間使用UI和BL以及Domain對象/實體之間的DTO。我理解你的解釋,我唯一缺少的觀點就是主要問題的答案 - 如何跟蹤複雜對象圖中的變化?你收到DTO,你必須以某種方式找到變化。如果你的DTO是簡單的對象,你不需要跟蹤它,但是如果DTO包含其他DTO的集合呢?您需要知道該集合中發生了什麼變化。 – 2010-08-13 07:49:39

+0

RE對象圖的變化 - 我期待有設計模式可以處理這個問題,但我無法回想起我的頭頂 - Momento想起來了,否則可能是事件驅動的模型? – 2010-08-26 20:16:03

+0

在傳統的ASP.NET模型中,頁面傾向於每次都從頭開始構建(因此無論更改什麼都要加載所有數據),並且如果要在視圖狀態中保存數據,則傾向於將其視爲「數據」 - 所以我一直沒有想要按照你建議的方式尋找具體的變化(?)。另一種方法是基於AJAX的方法,但這是相似的。觀察者模式也可能是有趣的。 – 2010-08-26 20:23:03

3

我們的體系結構是非常相似的你的,但是使用含有相同的域對象一個Silverlight客戶端(即沒有確切的 - 代碼共享)上的客戶端和服務器。我們的體系結構的關鍵點是在短

  • 客戶有域模型和更改是通過我自己來實現跟蹤框架(它使用AOP,這樣我可以在客戶端使用波蘇斯跟蹤;我不知道一個框架,我希望域模型是持久的無知)
  • 這整個模型存儲在客戶端上的一種遠程存儲庫。當我們保存這些更改時,將會提取一個更改樹(通過我的更改跟蹤框架),並使用匯編器將其轉換爲DTO(確切地說是DataContracts,但無關緊要)。 DTO具有跟蹤狀態標誌(新的,修改的,刪除的)。
  • 在服務器側(服務層通過WCF web服務實現的)的DTO的將被轉換爲域對象和連接到ORM(NHibernate的在我們的例子)。由於這個附加過程,我需要跟蹤狀態。通過ORM可以完成和保存更多的更改

目前很難將複雜圖形附加到ORM,但我希望原因是我沒有太多的使用NHibernate的經驗。

我們還沒有完成,但它似乎是有希望的。

對於數據訪問,我們試圖使用WCF Dataservices。但我認爲我們不會使用它們,因爲需求正在使用DataContract。這導致了從基於DataContract的LINQ查詢到基於域對象的LINQ查詢的轉換。如果領域模型和數據合同有很大差異(這在某些迭代中會出現這種情況),那麼實現起來並不方便也難以實現。

任何注意事項?