2010-04-17 149 views

回答

18

完美的例子是一個地址。使用複雜類型的地址比新實體更容易處理。對於複雜類型,您不必處理主鍵。考慮訪問地址有多少種常見類型的實體會有地址(業務單位,人員,地點)。想象一下,填充許多人的地址並需要爲每個人設置一個密鑰。對於複雜的類型,只需訪問它們的內部屬性即可完成。這是一個示例的MSDN鏈接。 http://msdn.microsoft.com/en-us/library/bb738613.aspx

+2

擁有複雜類型而不是普通標量屬性有什麼好處? – emzero 2010-04-29 01:01:10

+0

@emzero我猜他們很多,這基本上是一個OOD。您可能不想在發送貨件時在地址上定義get方法或將地址對象傳遞給某些其他方法。它也遵循DRY方法。假設你做了一個ToString()覆蓋,你只需要爲所有具有Address的類執行一次。 – 2012-04-13 15:07:08

+0

這難道不會讓所有不同的表的所有地址都難以執行操作嗎?如果我想添加地理位置數據,或者清理所有地址格式等?用這張獨立的桌子,這不是很容易嗎?或者你可以做一些像 repo.ComplexTypes.ToList() – 2013-03-18 08:52:00

0

基於域驅動設計概念,聚合根可以有一個或多個內部對象作爲其部分。在這種情況下,內部對象 - 在Aggregate Root的邊界內 - 沒有任何KEY。父鍵將應用於它們或以某種方式如此。您的答案返回到保持聚合根內所有零件的好處,使您的模型更健壯,更簡單。

+0

聚合根可能包含具有密鑰的實體。他們只屬於一個聚合根。 – 2015-03-28 11:18:54

10

這個問題已經出現了一段時間了,但我仍然會添加一個答案,希望隨之而來的下一個可憐的哭泣知道他在做什麼。

複雜類型不支持延遲加載,至少在EF 4.3中不支持延遲加載。我們以地址情況爲例。你有一個有15列的Person表,其中5個包含某些個人的地址信息。它有5萬條記錄。您爲具有複雜類型Address的表創建實體Person。

如果您需要在數據庫中的所有個人的名單,你會做

var records = context.Persons; 

其中還包括地址,抽5個* 50K值到你的列表中沒有任何理由,並用明顯的延遲。你可以選擇只加載您在一個匿名類型需要

var records = from p in context.Persons 
       select new { 
       LastName = p.LastName, 
       FirstName = p.FirstName, 
       } 

這對於這種情況下行之有效的值,但是如果你需要使用,也就是說,8個非地址欄一個更全面的列表,你要麼需要在匿名類型中添加每一個,或只是與第一個案例一起,並返回加載無用的地址數據。

這是關於匿名類型的事情:雖然它們在單個方法中非常有用,但它們強制您在類或子類的其他地方使用動態變量,這會取消Visual Studio的某些重構工具並讓您打開運行時間錯誤。理想情況下,您希望在您的方法中分發實體,以便這些實體儘可能少地攜帶行李。這就是爲什麼懶加載非常重要。

說到上面的例子,地址信息應該真正在它自己的表中,並且有一個完整的實體覆蓋它。作爲一個附帶好處,如果您的客戶要求第二個人的地址,您可以通過在Person中添加額外的地址引用將其添加到您的模型中。

如果不像上面的例子,你幾乎在每個查詢中都需要地址數據,並且真的想在Person表中有這些字段,那麼只需將它們添加到Person實體即可。你將不再擁有整潔的地址前綴,但它不完全是失去睡眠的東西。

但是等等,還有更多!

複雜類型是一種特殊情況,是普通EF實體平滑景觀中的顛簸。你項目中的那些人可能沒有資格從你的實體基類繼承,這使得他們不可能通過處理你的實體的方法來處理它們。

假設您有一個名爲EntityModel的實體基類,它定義了一個屬性ID。這是你的所有實體對象的關鍵,所以您現在可以創建

class EntityModelComparer<T> : IEqualityComparer<T> where T : EntityModel 

,你可以再從類型T的任何IQueryable的其中T是實體類鮮明的()來過濾重複使用。複合類型不能從EntityModel繼承,因爲它沒有ID屬性,但這很好,因爲無論如何你都不會使用獨特的。

更進一步,您遇到了一種情況,您需要某種方式來通過任何實體並執行操作。也許你想要在UI上動態列出一個實體的屬性,並讓用戶對它們執行查詢。所以你構建一個類可以實例化的特定類型,並將它採取了整個事情的護理:

public class GenericModelFilter<T> : where T : EntityModel 

哦,等一下,你的複雜類型的類型EntityModel的不是。現在,您必須將實體繼承樹複雜化以適應複雜類型或擺脫EntityModel合同並降低可見性。

一起移動,添加,基於用戶選擇你的類中的方法可以創建,你可以使用LINQ用於過濾任何實體類

Expression<Func<T, bool>> GetPredicate() { ... } 

所以現在你可以做這樣的事情的表達式:

personFilter = new GenericModelFilter<Person>(); 
companyFilter = new GenericModelFilter<Company>(); 
addressFilter = new GenericModelFilter<Address>(); //Complex type for Person 

... 

var query = from p in context.Persons.Where(personFilter.GetPredicate()) 
      join c in context.Companies.Where(companyFilter.GetPredicate()) on p.CompanyID = c.ID 
      select p; 

這對所有實體對象都是一樣的......除了有特殊需求的地址。你不能像對待公司一樣爲它加入。你可以從Person導航到它,但是你如何將它應用到它上面,最後還是Person?現在你必須花點時間想出一個簡單的系統,這個系統在其他地方很容易運行。

該模式在項目的整個生命週期中都會重複出現。我是否根據經驗說話?我希望我沒有。複雜的類型會阻止你的進步,就像班級背後的一個行爲不端的學生一樣,不會增加任何內容。自己幫忙,選擇實際的實體對象。