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