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

时间:2013-11-20 21:06:28

标签: c# sql linq entity-framework

我有这个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?

4 个答案:

答案 0 :(得分:8)

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

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)
    )

答案 1 :(得分:8)

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

答案 2 :(得分:7)

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

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

答案 3 :(得分:6)

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

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