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呢?
在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)
在EF6中,数据库空语义是默认的比较语义.请注意,这是对EF5中默认设置的更改.在EF5中,此标志隐藏在ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior中,默认情况下EF将使用Linq to Object比较语义.在EF6中,它在DbContext上公开为DbContext.Configuration.UseDatabaseNullSemantics.你可以在这里找到更多细节
WHERE条件是以这种方式生成的,因为使用ANSI NULLS设置,比较AssetTag == null不会返回SQL中的相应行(因为在SQL世界中,将null与null进行比较时结果为null).为了使查询行为与C#开发人员期望的相同,EF生成扩展的WHERE子句.请注意,以前版本的EF没有这样做,因此不适用于具有ANSI NULLS设置的数据库.
GroupBy投影就在那里,因为EF在.Count()调用之前支持更复杂的查询,例如连接,投影等.因此,这种方法更通用,因为它也适用于所有这些场景.
首先,c.AssetTag == assetTag如果两者都为空,那么在C#中将是真的.但是在SQL中,与任何事物相比,null始终为false.因此,如果我们想要生成一个遵循C#比较机制的查询,我们必须添加其他条件以确保null将evaluate与true比较为true,如果两者都为null:
([Extent1].[AssetTag] IS NULL) AND (@p__linq__0 IS NULL)