2010-10-14 57 views
3

看着分析器,我看到了一些差异。使用的第二个查询包括实际上将返回与辅助表CountryCodes相关的数据。这部分对我来说很有意义。但我不明白为什么这个查询有两个连接。首先它在CountryCodes和CountyCodeTypes(在外键上)之间进行常规的内连接,我认为这足以返回包括所需的所有内容。然而,它然后做另一个外部联接。为什么?这两个LINQ查询有什么区别?

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作为连接的手段,因为导航属性知道如何基于键来连接实体。

+2

这不是你的问题的SQL是否由第一或第二的LINQ查询生成非常清楚... – 2010-10-15 00:12:59

回答

4

这只是实体框架生成的SQL的本质。

INNER JOIN因您的where声明而存在。

where codes.CountryCodeType.CountryCodeTypeName == countryCodeType 

EF可以解决此问题的唯一方法是执行INNER JOIN,正如您正确指出的那样。您也注意到INNER JOIN确实返回了满足Include()所需的所有数据。

但是,外部连接仍然执行,只是因为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; 
+0

谢谢柯克。那么说这么说是公平的,那么你在没有连接的情况下提出的查询就等于我用JOIN编写的查询。但是,您的查询只是利用从数据模型推断的导航属性?我也明白你的意思是把'Include()'翻译成一个自动的OUTER JOIN。然而有一点想到。在两个表之间实际上存在外键约束的情况下,INNER JOIN不会足够吗? – e36M3 2010-10-15 00:36:48

+0

1 /您可以使用数据模型中描述的导航属性执行连接 - 我相信这是EF的一个中心特性。 2 /如果你没有做'where',那就没有INNER JOIN。如果你想用'Include'检索相关的对象,如果EF使用INNER JOIN,你只能检索那些有相关对象的对象。 OUTER JOIN确保您检索具有相关对象的那些,以及不包含那些(OUTER JOIN为空)的那些对象。 – 2010-10-15 00:54:38

2

由于codes.CountryCodeType.CountryCodeTypeName == countryCodeType的结果,左外连接发生,而内连接恰好允许它在最终结果中包含来自CountryCodeType表的字段。

如果在结果中不需要外键表中的数据,则不需要使用Include Join。如果你没有使用“包含”,它只会使用左外连接,而不是内连接。

我猜这个框架根本不够聪明,意识到它已经在该表上做了一个连接,并且可以重用那里的信息。希望SQL Server足够聪明,可以接受这一点,并使用执行计划来避免重复工作。

+0

难道我需要为我做的地方加入条件虽然? – e36M3 2010-10-15 00:09:08

+0

不是。该框架计算出您正在引用一个相关的表并在SQL中创建必要的连接,这只是基于属性访问。 – StriplingWarrior 2010-10-15 15:16:59

+0

我刚才意识到我有内连接和外连接向后。柯克的回答更为正确。 – StriplingWarrior 2010-10-15 15:18:26