2012-12-05 53 views
3

概述如何避免以便查詢基本類型有效

我第一次使用實體框架4.3的代碼與流暢的界面設置我的DbContext實體框架TPT遺傳多態行爲。我有一個基地項目類與其他類型的繼承這個如事件博文ForumThreadwiki頁面等。

這些繼承的類型映射與我認爲實體框架引用爲TPT繼承。當查詢單個類型(如'events'或'blog posts')時,此功能非常有用,但在嘗試跨所有類型進行查詢時會構造非常複雜的查詢,因爲需要進行連接才能實現EF提供的多態行爲。

問題背景

我想建立一個全球性的搜索功能,我只需要訪問基「項目」的實體,而不是繼承的實例。我希望能夠通過名稱,標籤等查詢基礎項目類。執行任何類型的LINQ查詢,即使在請求基類項目類型時仍會導致殺死性能的多態行爲。

守則第一種模式

public class Item 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public string Body { get; set; } 

    public DateTime Created { get; set; } 

    public int? CreatedBy { get; set; } 

    public int? LastModifiedBy { get; set; } 

    public DateTime? LastModified { get; set; } 

    public virtual User Author { get; set; } 

    public bool IsDeleted { get; set; } 

    public string ImageUri { get; set; } 

    public virtual ICollection<Tag> Tags { get; set; } 
} 

public class Event : Item 
{ 
    // Additional properties 
} 

public class BlogPost : Item 
{ 
    // Additional properties 
} 

我想做些什麼可以做的是另POCO映射到相同的基表,這樣,當我構造查詢就可以了,它不涉及的傳承的問題。 EF似乎並不喜歡這個。目前我手邊沒有這個錯誤,但是我對簡單映射的嘗試失敗了。

備用解決方案?

  • 我曾想過實施的「索引」表,該表看起來類似於「項目」表並插入一條記錄到,每當創建一個新的項目類型。但是,只要事件,博客文章數據發生變化等情況,此索引數據也需要更新等。外鍵(如標籤)使這種情況更加複雜。每當說事件發生變化時,我必須確保這些更改在匹配索引表上同步。當考慮所有不同的物品類型時,這將成爲一個管理和坦率的噩夢,似乎不是一個非常優雅的解決方案。

  • 數據庫觸發器

我首選的方案在這裏將是一個在代碼,而不是數據庫觸發器/存儲的特效。

有沒有辦法構建一個查詢來強制EF只返回基類型而不是多態類型,這會導致太多的連接和可怕的性能?還是有其他一些聰明的方法呢?

更新

經由的NuGet(靶向的.Net 4更新到的EntityFramework 5之後。0)我已經能夠通過它們的標籤查詢項目並投影到新的SearchItem,這導致相當乾淨的SQL,而不會連接到TPT類型。

 var x = from item in repository.FindAll<Item>() 
       where item.Tags.Any(t => t.Name == "test") 
       select new SearchItem 
       { 
        Id = item.Id, 
        Name = item.Name, 
        Body = item.Body, 
        Created = item.Created, 
        CreatedBy = item.CreatedBy, 
        IsDeleted = item.IsDeleted, 
        ImageUri = item.ImageUri, 
        MembershipEntityId = item.MembershipEntityId, 
        //Tags = (from t in item.Tags 
        //  select new Tag 
        //  { 
        //   Id = t.Id, 
        //   Name = t.Name, 
        //   MembershipEntityId = t.MembershipEntityId 
        //  }) 
       }; 

SQL

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
[Extent1].[Body] AS [Body], 
[Extent1].[Created] AS [Created], 
[Extent1].[CreatedBy] AS [CreatedBy], 
[Extent1].[IsDeleted] AS [IsDeleted], 
[Extent1].[ImageUri] AS [ImageUri], 
[Extent1].[MembershipEntityId] AS [MembershipEntityId] 
FROM [dbo].[Item] AS [Extent1] 
WHERE EXISTS (SELECT 
1 AS [C1] 
FROM [dbo].[ItemTag] AS [Extent2] 
INNER JOIN [dbo].[Tag] AS [Extent3] ON [Extent3].[Id] = [Extent2].[Tag_Id] 
WHERE ([Extent1].[Id] = [Extent2].[Item_Id]) AND (N'test' = [Extent3].[Name]) 
) 

這已經解決了問題的一半,因爲我可以在基本型的標籤現在搜索。然而,我希望能夠用新投影返回標籤。包括註釋掉的代碼會導致EF無法翻譯的查詢。有沒有解決方法?

回答

2

有沒有一種方法來構造查詢強制EF來只返回 基本類型,而不是多態類型,導致了太多 連接和可怕的表現如何?

一般沒有。您已映射繼承,並且如果要返回Item的實例,則EF必須始終返回正確的類型=>它需要這些連接。 EF也不允許多次映射同一個表,因此您不能在同一個映射中將Item再次映射爲另一個POCO。

從理論上講,您應該能夠查詢Items並項目到您的未映射您需要從基類獲得POCO類的唯一屬性。不幸的是,這在.NET 4.0中不起作用 - EF still performed joins。你可以在.NET 4.5和EF 5.0上試試這個問題,在這個問題上should be solved

+0

雖然投影到新的非映射類型可能適用於基本屬性(我會試試這個),但這不適用於相關標籤嗎? –

+0

我已根據您的答案更新了我的問題並提供了更多信息。這解決了一半的問題,你有沒有想過用投影的SearchItem返回標籤? –

+0

我將此標記爲更新EF版本的答案,並將其投影到具有有限屬性子集的新自定義類型,這確實解決了我的問題的很大一部分問題。然而,我仍然在尋找集合/導航屬性(如標籤)的解決方案。 –