我第一次使用實體框架4.3的代碼與流暢的界面設置我的DbContext實體框架TPT遺傳多態行爲。我有一個基地項目類與其他類型的繼承這個如事件,博文,ForumThread,wiki頁面等。
這些繼承的類型映射與我認爲實體框架引用爲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無法翻譯的查詢。有沒有解決方法?
雖然投影到新的非映射類型可能適用於基本屬性(我會試試這個),但這不適用於相關標籤嗎? –
我已根據您的答案更新了我的問題並提供了更多信息。這解決了一半的問題,你有沒有想過用投影的SearchItem返回標籤? –
我將此標記爲更新EF版本的答案,並將其投影到具有有限屬性子集的新自定義類型,這確實解決了我的問題的很大一部分問題。然而,我仍然在尋找集合/導航屬性(如標籤)的解決方案。 –