2011-12-13 205 views
1

我實現了在http://www.sqlteam.com/article/implementing-table-inheritance-in-sql-server表現出了表繼承功能。實體框架包含/加盟問題

所有的外鍵和約束到位。

現在我使用實體框架拉回來我的人,學生,教師和家長在模型看起來像下面這樣(沒有所有的EF特定的屬性等)。

public partial class People : EntityObject 
{ 
    public guid PeopleID { get; set; } 
    public int Age { get; set; } /Added for an example query 
    public PeopleParent Parent { get; set; } 
    public PeopleStudent Student { get; set; } 
    public PeopleTeacher Teacher { get; set; } 
} 

現在我需要讓所有的人不分類型,誰是25歲,不超過100條記錄,我想包括所有引用的數據。創建我的EF查詢,如:

IQueryable<People> query = Entities.People.Include("PeopleParent") 
              .Include("PeopleStudent") 
              .Include("PeopleTeacher"); 

query.Where(x => x.Age == 25) 
    .Take(100); 

IEnumerable<People> results = query.ToList(); 

看起來很簡單,但無論表/ EntitySet的我已經設置第一,包括創建一個INNER JOIN代替LEFT OUTER JOIN,這是不產生正確的結果。

生成TSQL(不正確的適合我的需要):

SELECT 
    [Limit1].[C1] AS [C1], 
    <A bunch of Limit1 Columns> 
FROM (
    SELECT TOP (100) 
    [Extent1].[PeopleID] AS [PeopleID], 
    <A bunch of Extent1 Columns> 
    [Extent2].[PeopleID] AS [PeopleID1], 
    <A bunch of Extent2 Columns> 
    [Extent3].[PeopleID] AS [PeopleID2], 
    <A bunch of Extent3 Columns> 
    [Extent4].[PeopleID] AS [PeopleID3], 
    <A bunch of Extent4 Columns> 
    1 AS [C1] 
    FROM [rets].[People] AS [Extent1] 
    INNER JOIN [rets].[PeopleParent] AS [Extent2] 
    ON [Extent1].[PeopleID] = [Extent2].[PeopleID] 
    LEFT OUTER JOIN [rets].[PeopleStudent] AS [Extent3] 
    ON [Extent1].[PeopleID] = [Extent3].[PeopleID] 
    LEFT OUTER JOIN [rets].[PeopleTeacher] AS [Extent4] 
    ON [Extent1].[PeopleID] = [Extent4].[PeopleID] 
) AS [Limit1] 

爲什麼首先包括用作INNER JOIN,並且是有soluion我的問題?

**更新1 **

假設我用拉吉斯拉夫Mrnka的Answer,也有因的LINQ和Lambda查詢顯著變化兩個額外的要求。

問:我如何尋找具有特定性質的特定的人?

(所有以 「A」 的高二學生)

答:

context.People.OfType<Student>().Where(s => s.Grade == "A"); 

問:我如何搜索具有特定屬性的任何人?

(所有學生或教師是誰的PrimaryFocus = 「數學」)

答:

List<People> result = new List<People>(); 
result.AddRange(context.People.OfType<Student>() 
           .Where(x => x.PrimaryFocus == "Math") 
           .ToList()); 
result.AddRange(context.People.OfType<Teacher>() 
           .Where(x => x.PrimaryFocus == "Math") 
           .ToList()); 

回答

6

你應該使用繼承原生支持EF明顯的解決方案。在你的情況TPT inheritance。一旦你有繼承,你可以簡單的叫:

IEnumerable<People> results = Entities.People 
             .Where(x => x.Age == 25) 
             .Take(100) 
             .ToList(); 

,它將返回你的StudentTeachersParents情況下,等

在您的解決方案的唯一建議是檢查的關係是可選的(1 - 0..1) - 。如果需要,它將使用INNER JOIN。如果它是可選的並且仍然使用INNER JOIN,那麼它可能是模型中的一些錯誤或其他問題。

+0

我一直沒有在EF中使用繼承支持。如果我選擇繼續使用這個「兔子洞」,如果我尋找'.Where(x => x.Grade ==「A」)',當父母和老師沒有時,它會如何影響搜索'Grade'屬性(僅限學生)? –

+0

您無法搜索「人物」,而是搜索「學生」:context.People.OfType ().Where(s => s.Grade ==「A」)'。繼承是棘手的,它具有顯着的性能成本(這將在.NET 4.5中得到改進),但它是數據庫的最佳解決方案。 –

+0

最後一個問題,我更新了實際的問題。 –