2010-09-27 97 views
3

我見過2種類型的實體的實體,利弊類類型FK,像這樣:把剛纔的密鑰類型(ID)或

public class Person 
{ 
    public int Id {get;set;} 
    public string Name {get;set;} 
    public Country Country {get;set;} 
} 

像這樣:

public class Person 
{ 
    public int Id {get;set;} 
    public string Name {get;set;} 
    public int CountryId {get;set;} 
} 

我認爲第二個方法是更輕便,你只有當你需要的相關數據;
你覺得哪一個更好?

回答

1

這取決於你想要什麼。如果你只想得到國家的身份證,那麼去第二種選擇。如果您確實想要使用導航屬性和/或延遲加載,請轉到第一個選項。

就個人而言,我使用實體框架,並結合選項之一,之二:

public class Person 
{ 
    public int Id {get;set;} 
    public string Name {get;set;} 
    public int CountryId {get;set;} 
    public Country Country {get;set;} 
} 

所以我有一個選擇,當談到從我的倉庫返回數據。這也意味着,當我來救,我可以填充,而不必加載國家對象,並將其分配給個人的實際值類型的屬性。

1

從表面,第一個是一個豐富的域模型的一個例子,第二個是數據驅動的方法。允許豐富的域模型是ORM的主要優點之一。

我將包括CountryId(或者代替國家或除此之外)的唯一原因將用於優化某些非常具體的性能問題。即使這樣,我也會考慮三次。優化是你在初始設計階段不應該考慮太多的問題。 Person.Country.Id有什麼問題? (假設你完全需要這個id,而不僅僅是基礎設施)。

如果是從比性能優化其他任何角度看這一點,那麼你可能通過在你的領域模型「外鍵」採取錯誤的做法。首次使用來自ADO類型背景的NHibernate時,我遇到了同樣的問題。我幾乎肯定會與第一個例子。

1

有兩個方面的考慮,平臺和流量,概述如下...

所有微軟平臺

在多層次的解決方案,在最終客戶是Silverlight和你要分享你的生成代碼通過RIA服務,或者你有WCF RIA服務的WPF客戶端,第一種解決方案爲你提供更好的設計。

非Microsoft最終客戶

如果您的最終客戶是不Microsoft客戶端一樣的Flex/Flash中,Java或任何基於AJAX的智能客戶端,那麼第一個模型不會因爲它需要跟蹤本身是有用的(自我跟蹤對象)。第二種模式在這裏是首選。

低流量的應用

如果網絡流量是沒有太大問題的,你的軟件設計,更重要的,還是你有高度可擴展的中間輪胎,高速緩存等,例如App面料等,首先解決好一個這會給你更好的設計。

高流量應用

第一個模型序列化更多的數據,然後根據需要,並且能夠在高流量應用的真正的性能問題。所以在這種情況下,第二種模式會更好,因爲只有當用戶請求更多的引用數據時,纔會加載它。

這是在「更好的設計」和「更好的性能」之間的一個折衷問題,它需要根據上面提到的參數進行選擇,根據項目的複雜程度,團隊規模,文檔和更多參數。

1

好問題!對我來說

public List<Person> GetPersonsLivingIn(int countryId) { 
    return ObjectContext.Persons.Where(x => x.CountryId == countryId).ToList(); 
} 

只是看起來像它這樣工作,無需瞭解所有的魔法(泄漏)的抽象可能存在的ORM,這將使x => x.Country == country工作。我來自Linq2Sql,當傳遞在不同的對象上下文中創建的對象時,我遇到了第一個問題。

但我會像GenericTypeTea說的那樣做,並且包括id和導航屬性。畢竟,你會希望在某個時候有一個可導航的對象圖。這樣你仍然可以製作更多OO感覺的界面,但仍然看起來像沒有魔法一樣工作。

+0

你稱之爲「魔術」的東西是ORM的核心。不使用它會創建一個貧血域模型,這是一種ORM反模式(IOW,如果您不使用它的功能,爲什麼要使用ORM?) – 2010-09-27 15:01:19

+0

感謝您的評論。從我的角度來看,在方法接口中暴露實體對象會給方法開發者帶來一個問題:實體是否來自同一個對象上下文?我可以重新附加到我自己的嗎?實體中加載了什麼部分的對象圖?我可以延遲加載實體的其他部分/是實體的對象上下文還活着嗎? ORM增加了很多複雜性,我已經幾次將我的手指燒在我認爲可行的事情上,但沒有。 – Andreas 2010-09-27 16:29:10

+0

您描述的所有問題都來自錯誤的會話管理。我並不是說每個人都能夠直觀地掌握基本概念,但是汽車的比喻應該已經到位。 – 2010-09-27 18:28:43

1

除了在一些奇怪的邊緣情況下,第二種設計沒有很好的理由。

它們都是同樣輕量級的(默認情況下引用是延遲加載的),但第二個不會提供導航功能,這會限制查詢並使其複雜化。

1

停止!

在NHibernate中,有NO需要在你的領域模型指定外鍵,即使不是出於性能的考慮。

假設你有懶加載啓用(它是默認啓用),稱:

int countryId = person.Country.Id; 

... 不會招致命中檢索國家實體的數據庫。 NHibernate將返回您的客戶的動態代理,而不是實際的客戶。由於代理服務器的原因,數據庫命中只會在首次訪問客戶實體上的Property時發生,但NHibernate足夠聰明地認識到'person.Country.Id'與訪問Person中的客戶ID外鍵相同表,無論如何都會被加載。

但是,下面的代碼:

string countryName = person.Country.Name; 

...將達到數據庫,調用的「名稱」屬性將加載整個客戶實例。

這種行爲假定您已經設置好你的映射像這樣:

<many-to-one name="Country" class="Country" column="Country_ID" lazy="proxy" /> 

(注意,爲lazy =「代理」是默認值)。

簡而言之,不需要將域模型中的外鍵映射到NHibernate。