實體框架複雜類型與創建新實體

.net .net-4.0 c# entity-framework

我正在閱讀有關Entity Framework 4.0的內容,我想知道為什麼要創建複雜類型而不是新實體(表)以及它們之間的關係?

一般承認的答案

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


熱門答案

這個問題已經存在了一段時間了,但無論如何我都會補充一個答案,希望下一個可憐的嗚咽知道他在做什麼。

複雜類型不支持延遲加載,至少在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

然後,您可以使用Distinct()從類型為T的任何IQueryable中過濾重複項,其中T是實體類。複雜類型不能從EntityModel繼承,因為它沒有ID屬性,但這很好,因為無論如何你都不會在它上面使用distinct。

更進一步,您會遇到需要某種方式通過任何實體並執行操作的情況。也許您想要在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結尾?現在你需要花點時間找出這個特殊情況,這個系統可以在其他任何地方輕鬆使用。

這種模式在項目的整個生命週期中都會重複出現。我是從經驗中說話嗎?我希望我沒有。複雜的類型會阻止你的進步,比如課後的一個行為不端的學生,而不會添加任何本質的東西。幫個忙,選擇實際的實體對象。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因