为什么Entity Framework 6为简单查找生成复杂的SQL查询?

我有这个LINQ查询

dbContext.Customers.Where(c => c.AssetTag == assetTag).Count(); 

要么

 (from c in dbContext.Customers where c.AssetTag == assetTag select c).Count(); 

生成的SQL是

 SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[Customer] AS [Extent1] WHERE (([Extent1].[AssetTag] = @p__linq__0) AND ( NOT ([Extent1].[AssetTag] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent1].[AssetTag] IS NULL) AND (@p__linq__0 IS NULL)) ) AS [GroupBy1] 

那么为什么LINQ会为一个简单的where语句生成如此复杂的SQL呢?

在EF6中,数据库空语义是默认的比较语义。 请注意,这是对EF5中默认设置的更改。 在EF5中,此标志隐藏在ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior中 ,默认情况下EF将使用Linq to Object比较语义。 在EF6中,它在DbContext上公开为DbContext.Configuration.UseDatabaseNullSemantics 。 你可以在这里找到更多细节

在C#string equivalency中, null == null计算结果为True 。 数据库中的null == null计算结果为False 。 该脚本将validation列值和参数是否为空,或者两者都不为空且它们具有相同的字符串值。

 WHERE ( -- neither the column nor the paramter are null and -- the column and the parameter have the same string value ([Extent1].[AssetTag] = @p__linq__0) AND ( NOT ([Extent1].[AssetTag] IS NULL OR @p__linq__0 IS NULL)) ) OR ( -- both the column value and the parameter are null ([Extent1].[AssetTag] IS NULL) AND (@p__linq__0 IS NULL) ) 

WHERE条件是以这种方式生成的,因为使用ANSI AssetTag == null设置,比较AssetTag == null将不会返回SQL中的相应行(因为在SQL世界中,将null与null进行比较时结果为null)。 为了使查询行为与C#开发人员期望的相同,EF生成扩展的WHERE子句。 请注意,以前版本的EF没有这样做,因此不适用于具有ANSI NULLS设置的数据库。

GroupBy投影就在那里,因为EF在.Count()调用之前支持更复杂的查询,例如连接,投影等。因此,这种方法更通用,因为它也适用于所有这些场景。

首先,在C# c.AssetTag == assetTag ,如果两者都为null, c.AssetTag == assetTag true。 但是在SQL中,与任何事物相比,null始终为false。 因此, 如果我们想要生成一个遵循C#比较机制的查询 ,我们必须添加其他条件以确保null如果两者都为null,则将evaluate与true进行比较:

([Extent1].[AssetTag] IS NULL) AND (@p__linq__0 IS NULL)