假设我有这句话:
var eggs = db.Nests.Single(b => b.id = 20).Birds.FirstOrDefault().Eggs;
在我的探查器跟踪中,我看到有多个命令正在执行:
SQL:BatchString
SELECT TOP (2)
[Extent1].[id]
...
FROM [dbo].[Nest] AS [Extent1]
WHERE 20 = [Extent1].[id]
SQL:BatchCompleted
RPC:Completed
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
...
FROM [dbo].[Bird] AS [Extent1]
WHERE [Extent1].[NesId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=20
RPC:Completed
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
...
FROM [dbo].[Egg] AS [Extent1]
WHERE [Extent1].[BirdId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=13
是否所有这些命令都在同一个请求中执行,或者每个命令都是往返的?
此外,我是否可以确认这是编写上述内容的最有效方式:
var eggs = db.Nests.Include("Birds")
.Single(b => b.id = 20)
.Birds.Include("Eggs")
.FirstOrDefault()
.Eggs;
或者明确的加入会更好吗?
答案 0 :(得分:2)
首先,在第一个示例中获得多个查询是完全正常的。除非您在第二个示例中使用Include()
,否则访问任何导航属性都会生成新的SQL查询。
我不确定您的数据库架构是如何布局的,但假设Birds
有一个名为Nests
Id_Nest
的外键,您可以将此查询重写为:
var eggs = db.Birds.Include("Eggs")
.First(x => x.Id_Nest == 20)
.Eggs
.ToList();
Include()
生成的代码与显式join
的代码相同,因此无需担心代码不同。至于往返,如果你的意思是网络服务器和数据库之间的往返,那么是的,每个查询可能有一个往返。如果连接保持打开,这并不是一件大事。但最好是通过join
或Include()
一次性获取所需的一切,而不是将数据库击中3次。
答案 1 :(得分:1)
您在问题中描述的行为是lazy-loading功能的典型示例,该功能有助于快速构建工作的代码,但执行效果不佳因为远非最佳。作为旁注,我个人总是建议完全停用延迟加载。
是否所有这些命令都在同一个请求中执行,或者是 每个都往返一次吗?
是的,每次请求都有一次往返。在你的例子中,这可能不是什么大问题,但想象你的代码在一个循环中......你将你拥有的请求数(3)乘以迭代次数。你最终可能会收到成千上万的请求。
此外,我能否确认这是最有效的 写上面的方法:
这不是编写查询的最有效方法。实际上它可能甚至不会编译(你不能像你那样使用Include
)。
作为一般性建议,最有效的方法是包含您需要的所有导航属性,然后,只有这样,才能使用单个ToList
/ {{来执行查询 1}} / Single
或实际执行查询并实现实体的任何函数。所以你只有一个SQL请求。
对于您提供的具体示例,@ Radu Porumb建议可能是生成最简单/最有效的SQL的查询。当然,您必须使用分析器验证此假设。