查看分析器,我看到了一些差异。使用 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,否则使用连接?换句话说,我不应该使用.Include作为连接的手段,因为导航属性知道如何根据键为我加入实体。
答案 0 :(得分:4)
这只是实体框架生成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;
答案 1 :(得分:2)
左外连接是codes.CountryCodeType.CountryCodeTypeName == countryCodeType
的结果,而内连接恰好允许它在最终结果中包含CountryCodeType表中的字段。
如果您不需要结果中外键表中的数据,则无需使用Include 或 Join。如果你没有使用“Include”,它只会使用左外连接,而不是内连接。
我猜这个框架根本不够聪明,无法意识到它已经在该表上完成了连接,并且可以在那里重用信息。希望SQL Server足够聪明,可以接受并使用执行计划,避免重复这种努力。