從我所能理解的,你的問題源於你有一個由你的DTO製作的本地顯式聲明的對象圖的事實。我的意思是你已經在你的Country
模型上聲明public Unit Unit { get; set; }
(不知道你爲什麼聲明它們是virtual
,但這與手頭的問題沒有直接關係),而不是嘗試一種方法來保證對象圖簡化爲簡併案例的單個對象圖節點。
例如,考慮形式public UnitID Unit { get; set; }
定義每「參照」財產上的模型,其中UnitID
實際上可能int
或Guid
或者你用它來相互唯一識別和區分Unit
模型。只要你有一個引用或一組引用另一個模型,用它的標識符類型而不是它的實際類型替換它。這種策略適用於一套持久的模型,例如從/到每個模型具有身份密鑰的數據庫。這樣做可以讓你簡單的序列化,而不必擔心循環引用,因爲它們現在是不可能的。從技術上講,沒有更多的引用(即直接引用;它們現在是間接引用)。我們現在只是在您的領域模型設計中添加一個間接層。現在我們來適應那個間接層。
既然你聲稱你對貧血域模型方法很好,那麼這應該與此相適應。你付出的間接的未成年人(恕我直言)成本模型的設計和交易它的主要(恕我直言)基於接口的方法的好處數據檢索:
public interface IUnitRepository {
Unit GetUnit(UnitID id);
IEnumerable<Unit> GetUnits(IEnumerable<UnitID> ids);
// etc.
}
在你的消費者的代碼(即代碼使用此接口和域模型),通過執行接口調用以獲取由間接引用指向的基礎模型來遍歷隱含對象圖只會稍微複雜一些。
BEFORE:
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit;
AFTER:
// Somewhere earlier in your code, i.e. not *every* time this type of code appears
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = repo.GetUnit(ct.UnitID);
如果這句法困擾你,你可以定義上鍵入形式的Country
一套擴展的方法:
public static Unit Unit(this Country c, IUnitsRepository repo) {
return repo.GetUnit(c.UnitID);
}
擴展方法後:
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit(repo);
基於接口的方法可以爲您帶來經典的一系列優點,如關注點分離,可測試性,消費者與生產者絕緣等等。此外,您現在可以通過接口的實現類型更直接地控制對象的生命週期。我的意思是,你不應該假設你的Unit GetUnit(UnitID id)
方法的實施是天真的。此方法現在可以使用與SomeUnitsRepositoryImpl
的實例綁定的Dictionary<UnitID, Unit>
執行一些本地內存緩存。
有點囉嗦,但我希望它有幫助。彷彿從提供的細節數量來看,這並不明顯,我目前正在我的工作地點開展這項設計,以處理我們的記錄數據庫系統。 :)我真的非常喜歡它給我所有的靈活性,只需在域模型的設計中增加一層間接尋址的簡單代價。
好吧,所以屬性是虛擬的原因是因爲我正在使用和ORM(NHibernate在這種情況下),它需要我的POCO國家對象,並圍繞它建立一個代理來自動掛鉤延遲加載相關對象(即單位這個案例)。現在,我可以讓Country對象與您聲明的任何其他模型沒有關係,但這意味着要手動創建所有這些管道工作。這對我來說不是一個好的折衷,因爲我認爲序列化程序應該足夠靈活,可以讓我採用複雜的模型,只顯示我選擇的內容。我最終選擇了AutoMapper – Owen 2009-12-21 23:06:25