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

Vin*_*nde 7 c# sql linq entity-framework

我有这个LINQ查询

dbContext.Customers.Where(c => c.AssetTag == assetTag).Count();
Run Code Online (Sandbox Code Playgroud)

要么

(from c in dbContext.Customers
 where c.AssetTag == assetTag
 select c).Count();
Run Code Online (Sandbox Code Playgroud)

生成的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]
Run Code Online (Sandbox Code Playgroud)

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

Moh*_*oho 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)
    )
Run Code Online (Sandbox Code Playgroud)


Paw*_*wel 8

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

  • 你链接的msdn帮助页面说'DbContextConfiguration.UseDatabaseNullSemantics`的默认值是false - 所以在EF6数据库中,null语义不是默认的比较语义? (2认同)

Kna*_*ģis 7

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

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


Aar*_*nLS 6

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

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