为啥 Entity Framework 6 会为简单的查找生成复杂的 SQL 查询?
Posted
技术标签:
【中文标题】为啥 Entity Framework 6 会为简单的查找生成复杂的 SQL 查询?【英文标题】:Why does Entity Framework 6 generate complex SQL queries for simple lookups?为什么 Entity Framework 6 会为简单的查找生成复杂的 SQL 查询? 【发布时间】:2013-12-05 02:23:09 【问题描述】:我有这个 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?
【问题讨论】:
您的[AssetTag]
列是否允许为null
?。
对我来说似乎并不复杂,它只是创建一个语句来保护您的呼叫免受空范围的影响
您能告诉我如何从 Linq 或 Lamda 获取此 SQL 查询吗?这与您的问题完全无关,但我无法获得。
@e10 您可以使用 ToTraceString 方法 (msdn.microsoft.com/en-us/library/…) 或 LINQPad 之类的工具。
【参考方案1】:
在 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)
)
【讨论】:
谢谢大家的解释【参考方案2】:在 EF6 中,数据库空语义是默认的比较语义。请注意,这是对 EF5 中默认设置的更改。在 EF5 中,该标志隐藏在 ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior 中,默认情况下 EF 将使用 Linq 到 Object 比较语义。在 EF6 中,它在 DbContext 上公开为 DbContext.Configuration.UseDatabaseNullSemantics。您可以找到更多详情here
【讨论】:
您链接的 msdn 帮助页面显示DbContextConfiguration.UseDatabaseNullSemantics
的默认值为 false ——因此在 EF6 数据库中,空语义不是默认比较语义?【参考方案3】:
WHERE 条件是这样生成的,因为使用 ANSI NULLS 设置,比较 AssetTag == null
将不会返回 SQL 中的相应行(因为在 SQL 世界中,当比较 null 与 null 时,结果为 null)。为了使查询行为与 C# 开发人员期望的相同,EF 生成扩展的 WHERE 子句。请注意,早期版本的 EF 没有这样做,因此不适用于具有 ANSI NULLS 设置的数据库。
之所以存在 GroupBy 投影,是因为 EF 在 .Count() 调用之前支持更复杂的查询,例如连接、投影等。因此这种方法更通用,因为它也适用于所有这些场景。
【讨论】:
本来想解释一下范围的,虽然了解的很肤浅,但是不知道怎么解释。 +1 说得如此优雅。 +1 提到 6 之前的 EF不 这样做。【参考方案4】:一方面,在 C# 中,c.AssetTag == assetTag
如果两者都为空,则为真。然而,在 SQL 中,与任何事物相比,null 总是错误的。因此,如果我们想要生成一个遵循 C# 比较机制的查询,我们必须添加额外的条件来确保 null 比较在两者都为 null 时评估为 true:
([Extent1].[AssetTag] IS NULL) AND (@p__linq__0 IS NULL)
【讨论】:
以上是关于为啥 Entity Framework 6 会为简单的查找生成复杂的 SQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Entity framework Entity Master Details Entity Edit
为啥我的 Entity Framework Code First 代理集合为空,为啥我不能设置它?
为啥在我运行迁移时 Entity Framework 包会自动更新?
为啥我必须为 Code First / Entity Framework 提供无参数构造函数