2012-06-11 40 views
0

我正在使用Entity Framework處理更大的系統。就我個人而言,我喜歡編寫LINQ/ESQL查詢的基於方法的語法。如何在Entity SQL中使用基於方法的語法編寫正確連接的查詢?

但我cannnot弄清楚,如何加入下面的查詢可以正確編寫。

想,我有以下實體類和的DbContext庫:

public class A 
{ 
    [Key] 
    public int ID{get;set;} 
    public virtual ICollection<B> BCollection { get; set; } 
} 
public class B 
{ 
    [Key] 
    public int ID { get; set; } 
    public virtual A A { get; set; } 
    public virtual ICollection<C> CCollection { get; set; } 
    public virtual ICollection<D> DCollection { get; set; } 
} 
public class C 
{ 
    [Key] 
    public int ID { get; set; } 
    public virtual B B { get; set; } 
} 
public class D 
{ 
    [Key] 
    public int ID { get; set; } 
    public virtual B B { get; set; } 
} 
public class Entities : DbContext 
{ 
    public DbSet<A> SetA { get; set; } 
    public DbSet<B> SetB { get; set; } 
    public DbSet<C> SetC { get; set; } 
    public DbSet<D> SetD { get; set; } 
} 

現在我想「整」樹:A類的所有項目,與它們連接的B類項目,其中每個B類項目配備了C類的項目和D.

我能做到這一點與此查詢:

var x = db.SetA 
      .Include(a => a.BCollection.Select(b => b.CCollection)) 
      .Include(a => a.BCollection.Select(b => b.DCollection)) 
      .ToList(); 

但我認爲這是可以做到更容易,對不對?

請注意:我想加載整個樹,因爲我不想使用延遲加載。

編輯:

這不是關於一個單一的問題一個問題,我的問題是更多的辦法。當我寫我的查詢,如上面所示,EF產生一個巨大的查詢的地獄:

SELECT [Project3].[ID] AS [ID], 
    [Project3].[C9] AS [C1], 
    [Project3].[C2] AS [C2], 
    [Project3].[C3] AS [C3], 
    [Project3].[C4] AS [C4], 
    [Project3].[C1] AS [C5], 
    [Project3].[C5] AS [C6], 
    [Project3].[C6] AS [C7], 
    [Project3].[C7] AS [C8], 
    [Project3].[C8] AS [C9] 
FROM (SELECT [Extent1].[ID]  AS [ID], 
      [UnionAll1].[C1] AS [C1], 
      [UnionAll1].[ID] AS [C2], 
      [UnionAll1].[ID1] AS [C3], 
      [UnionAll1].[A_ID] AS [C4], 
      [UnionAll1].[ID2] AS [C5], 
      [UnionAll1].[B_ID] AS [C6], 
      [UnionAll1].[C2] AS [C7], 
      [UnionAll1].[C3] AS [C8], 
      CASE 
      WHEN ([UnionAll1].[ID] IS NULL) THEN CAST(NULL AS int) 
      ELSE 1 
      END    AS [C9] 
    FROM [dbo].[A] AS [Extent1] 
      OUTER APPLY (SELECT CASE 
           WHEN ([Extent3].[ID] IS NULL) THEN CAST(NULL AS int) 
           ELSE 1 
           END    AS [C1], 
           [Extent2].[ID] AS [ID], 
           [Extent2].[ID] AS [ID1], 
           [Extent2].[A_ID] AS [A_ID], 
           [Extent3].[ID] AS [ID2], 
           [Extent3].[B_ID] AS [B_ID], 
           CAST(NULL AS int) AS [C2], 
           CAST(NULL AS int) AS [C3] 
         FROM [dbo].[B] AS [Extent2] 
           LEFT OUTER JOIN [dbo].[C] AS [Extent3] 
           ON [Extent2].[ID] = [Extent3].[B_ID] 
         WHERE [Extent1].[ID] = [Extent2].[A_ID] 
         UNION ALL 


         SELECT 2     AS [C1], 
           [Extent4].[ID] AS [ID], 
           [Extent4].[ID] AS [ID1], 
           [Extent4].[A_ID] AS [A_ID], 
           CAST(NULL AS int) AS [C2], 
           CAST(NULL AS int) AS [C3], 
           [Extent5].[ID] AS [ID2], 
           [Extent5].[B_ID] AS [B_ID] 
         FROM [dbo].[B] AS [Extent4] 
           INNER JOIN [dbo].[D] AS [Extent5] 
           ON [Extent4].[ID] = [Extent5].[B_ID] 
         WHERE [Extent1].[ID] = [Extent4].[A_ID]) AS [UnionAll1]) AS [Project3] 
ORDER BY [Project3].[ID] ASC, 
     [Project3].[C9] ASC, 
     [Project3].[C3] ASC, 
     [Project3].[C1] ASC 

但我居然會寫我自己是這樣的:

SELECT  * 
FROM   D RIGHT OUTER JOIN 
        B ON D.B_ID = B.ID LEFT OUTER JOIN 
        C ON B.ID = C.B_ID RIGHT OUTER JOIN 
        A ON B.A_ID = A.ID 

我希望這有助於澄清我題。重點是:如何讓Entity Framework生成更高效的查詢?

+0

嗯,你的樹,在不改變惰性加載的配置,您的解決方案是好的(但它的會是一個「重」SQL請求...) –

+0

當然,我不想使用懶加載。比10.000個輕量級請求更重要的一個請求。但是你是對的,結果是一個包含三個子查詢和很多UNION的大型查詢。那我怎麼能改進呢? – ckonig

+0

你可以嘗試使用一個匿名對象('db.SetA.Select(seta => new {a = seta,bcoll = seta.BCollection'等),並測試它是否更快)如果perf是FINAL問題..使用「hard written」sql請求 –

回答

1

我認爲以下LINQ會產生你正在尋找一個「超級」查詢:如果你想「渴望負荷」

var query = 
     db.SetA 
      .Join(db.SetB, a => a, b => b.A, (a, b) => new 
                  { 
                   A = a, 
                   B = b 
                  }) 
      .Join(db.SetC, ab => ab.B, c => c.B, (ab, c) => new 
                   { 
                    A = ab.A, 
                    B = ab.B, 
                    C = c 
                   }) 
      .Join(db.SetD, abc => abc.B, d => d.B, (abc, d) => new 
                    { 
                     A = abc.A, 
                     B = abc.B, 
                     C = abc.C, 
                     D = d 
                    }); 

    foreach (var abcd in query) 
    { 
     Console.WriteLine("{0}-{1}-{2}-{3}", abcd.A.ID, abcd.B.ID, abcd.C.ID, abcd.D.ID); 
    } 
+0

有趣......但仍然,這給了我一個投影,我需要映射到實體樹中。 – ckonig

+0

好的。你期望什麼?類似「Tuple ''? –

+0

正是我會得到'變種X = db.SetA .INCLUDE(A => a.BCollection.Select(B => b.CCollection)) .INCLUDE(A => a.BCollection.Select(B = > b.DCollection)) .ToList();':對象,其導航屬性設置,所以我可以工作面向對象馬上沒有映射 – ckonig