这两个LINQ查询有什么区别?

3

看到分析器,我发现有几个不同之处。使用include的第二个查询实际上会返回与次要表CountryCodes相关的数据。这部分对我来说很有意义。然而,我不明白为什么这个查询有两个连接。首先,它在CountryCodes和CountyCodeTypes之间进行常规内连接(根据外键),我认为这足以返回include所需的所有内容。但是它随后又进行了另一个外连接。为什么呢?

var query = from codes in base.context.CountryCodes
            join codeTypes in base.context.CountryCodeTypes
            on codes.CountryCodeTypeId equals codeTypes.CountryCodeTypeId
            where codeTypes.CountryCodeTypeName == countryCodeType
            select codes;

var query = from codes in base.context.CountryCodes.Include("CountryCodeType")
            where codes.CountryCodeType.CountryCodeTypeName == countryCodeType
            select codes;

生成的 SQL 语句:

 FROM   [dbo].[CountryCode] AS [Extent1]
 INNER JOIN [dbo].[CountryCodeType] AS [Extent2] ON [Extent1].[CountryCodeTypeId] = [Extent2].[CountryCodeTypeId]
 LEFT OUTER JOIN [dbo].[CountryCodeType] AS [Extent3] ON [Extent1].[CountryCodeTypeId] = [Extent3].[CountryCodeTypeId]
 WHERE [Extent2].[CountryCodeTypeName] = @p__linq__0

此外,我可以说只有当我需要在结果中填充外键表中的数据时才应该使用.Include,否则应该使用join吗?换句话说,我不应该将.Include用作连接的手段,因为导航属性知道如何根据键连接实体。

2
你的问题并不是很清楚,无法确定SQL查询语句是由第一个还是第二个Linq查询生成的。 - Thomas Levesque
2个回答

4

这只是Entity Framework生成的SQL的本质。

INNER JOIN是由于您的where语句存在。

where codes.CountryCodeType.CountryCodeTypeName == countryCodeType

EF唯一能解决这个问题的方法是执行INNER JOIN,正如你所指出的那样。你还正确地指出了INNER JOIN确实返回了满足Include()的所有数据。
然而,OUTER JOIN仍然会被执行,因为EF看到了一个Include()并将其解析为需要连接。考虑一种情况,即您没有where子句 - 那么您就需要一个OUTER JOIN,对吗?好吧,EF无法聪明地确定在这种情况下不需要OUTER JOIN;它看到了一个Include(),然后生成相关的OUTER JOIN以确保满足数据要求。换句话说,它不考虑查询的其余部分来确定是否需要连接 - 它只是不管三七二十一就执行它。
关于Include()操作符,只有当您想要检索与您的应用程序相关的对象时才会使用它。这个查询不需要它。在这种情况下,最简单的查询方式是:
var query = from codes in base.context.CountryCodes
            where codes.CountryCodeType.CountryCodeTypeName == countryCodeType
            select codes;

谢谢你Kirk。那么,可以这样说你建议的查询如果没有使用JOIN,与我用JOIN写的查询是相等的吗?然而,你的查询只利用了数据模型推断出的导航属性?我也理解你所说的Include()会转化为自动OUTER JOIN。但是有一件事情让我想起来了。在任何存在两个表之间外键约束的情况下,INNER JOIN不就足够了吗? - e36M3
1/ 你可以使用数据模型中描述的导航属性执行连接操作 - 我认为这是 EF 的一个核心特性。 2/ 如果你没有进行 where 操作,就不会有 INNER JOIN。如果你想使用 Include 检索相关对象,如果 EF 使用了 INNER JOIN,那么你只能检索到具有相关对象的对象。OUTER JOIN 确保你检索到既有相关对象又有没有相关对象(外连接为空)的对象。 - Kirk Broadhurst

2

左外连接是由于 codes.CountryCodeType.CountryCodeTypeName == countryCodeType 而产生的,而内连接是为了让它在最终结果中包括 CountryCodeType 表中的字段。

如果您不需要来自外键表的数据,请不要使用 Include Join。如果没有使用 "Include",它只会使用左外连接,而不是内连接。

我猜这个框架可能只是没有足够聪明,意识到它已经在该表上进行了连接,并可以重用那里的信息。希望SQL Server足够聪明,选择避免重复努力的执行计划。


我需要使用连接才能执行我的where条件吗? - e36M3
不需要。框架会自动识别您正在引用相关表,并根据属性访问在SQL中创建必要的连接。 - StriplingWarrior
我刚意识到我把内连接和外连接搞反了。Kirk的答案更正确。 - StriplingWarrior

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接