不包括导航属性和数据库往返行程



假设我有这行:

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;

还是明确加入会更好?

首先,在第一个示例中获得多个查询是非常正常的。除非像第二个示例中那样使用Include(),否则访问任何导航属性都会生成一个新的SQL查询。

我不确定你的数据库模式是如何布局的,但假设Birds有一个名为Id_NestNests外键,你可以将这个查询重写为:

var eggs = db.Birds.Include("Eggs")
                   .First(x => x.Id_Nest == 20)
                   .Eggs
                   .ToList();

Include()生成与显式join大致相同的代码,因此无需担心代码不同。至于往返,如果你指的是web服务器和数据库之间的往返,那么是的,每个查询可能都有一个往返。不过,如果连接保持开放,那也没什么大不了的。但最好是通过joinInclude()一次性获得所需的一切,而不是三次点击数据库。

您在问题中描述的行为是延迟加载功能的一个典型示例,该功能有助于快速构建工作但执行较差的代码,因为性能远未达到最佳。顺便说一句,我个人总是建议完全停用懒惰加载。

所有这些命令是在同一个请求中执行的,还是每个都有往返行程吗?

是的,每个请求有一个往返行程。在您的示例中,这可能不是什么大不了的事情,但想象一下您的代码在一个循环中。。。您将拥有的请求数(3)乘以迭代次数。你最终可能会收到成千上万的请求。

此外,我能确认这是最有效的吗写上面的方法:

这不是编写查询的最有效方法。实际上,它可能甚至不会编译(您不能像以前那样使用Include)。

作为一般建议,最有效的方法是包括您需要的所有导航属性,然后,并且只有在那时,使用单个ToList/Single/First或实际执行查询并具体化实体的任何函数来执行查询。所以您只有一个SQL请求。

对于您给出的具体示例,@Radu Porumb建议可能是生成最简单/最高效SQL的查询。当然,您必须使用探查器来验证这个假设。

最新更新