我正在使用Entity Framework开发更大的系统。就个人而言,我确实喜欢编写LINQ / ESQL查询的基于方法的语法。
但我无法弄清楚,以下加入的查询如何正确编写。
假设我有以下实体类和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
我希望这有助于澄清我的问题。关键是:我如何使实体框架生成更有效的查询?
答案 0 :(得分: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);
}