与布尔值 false 进行比较时,如何防止 Linq2Sql 否定位列?

Posted

技术标签:

【中文标题】与布尔值 false 进行比较时,如何防止 Linq2Sql 否定位列?【英文标题】:How can I prevent Linq2Sql from negating bit columns when comparing to boolean false? 【发布时间】:2021-03-21 09:39:18 【问题描述】:

Linq2Sql 的一个非常烦人的特性是,当比较 BIT 列和布尔值 false 时,生成的 T-SQL 出于某种原因总是否定评估,例如:

CREATE TABLE SomeType
(
  MyInt INT NOT NULL PRIMARY KEY, 
  MyBool BIT NOT NULL
)

哪个 Linq 映射到了该类型:

public class SomeType
 
  public int MyInt ...
  public bool MyBool ...

使用针对该表的 Linq 查询,例如:

var db = new MyLinqContext(...);
var q = db.SomeTypes.Where(x => !x.MyBool);

总是会产生类似的东西:

SELECT [t0].[MyInt], [t0].[MyBool]
FROM [SomeType] AS [t0]
WHERE (NOT ([t0].[MyBool] = 1))

这种愚蠢和落后的(NOT (field = 1)) 构造倾向于弄乱我的查询计划和索引,但Linq2Sql 似乎一心想要以复杂的方式来做,而不是使用对索引更友好和更直接的(field = 0)。 您可能很想尝试一些变体,例如:

var b = false;
...Where(x =>
x.MyBool == false ||
x.MyBool != true ||
x.MyBool == b ||
!!!x.MyBool

...甚至更奇特的技巧,但它们都转化为相同的 (NOT (field = 1)) 或更糟。

有没有一种秘密的方法来鼓励 Linq2Sql 生成一个直接的、非否定的布尔比较而不弄乱 DBML 或映射的属性?

【问题讨论】:

这是 LINQ to SQL 还是 EF? @mjwills 这是普通的旧 Linq2Sql 【参考方案1】:

我写这一切只是为了分享这个词。在尝试了几乎所有可以想象的方式之后,我已经接近了。这是我迄今为止最好的镜头:

var q = db.SomeTypes.Where(x => x.MyBool.CompareTo(0) == 0);

虽然不直观,但它会生成类似的 T-SQL:

DECLARE @p0 Int = 0
SELECT [t0].[MyInt], [t0].[MyBool]
FROM [SomeType] AS [t0]
WHERE [t0].[MyBool] = @p0

不幸的是,我们失去了字面比较,但我们也删除了标量操作,这可以在一个古怪的查询计划中产生很大的不同。显然,现在比较的是 INT 参数和 BIT 列,但查询优化器似乎发现这些数据类型完全兼容。

有趣的是,虽然这显然是生成直接 T-SQL 的唯一方法,但如果直接在 .Net CLR 中进行评估,相同的代码将失败并出现 ArgumentException:

var x = new SomeType();
x.MyBool.CompareTo(0); // ArgumentException: Object must be of type Boolean.

但是哦,我们为查询计划所做的事情......

【讨论】:

显然,如果您可以使用CompiledQuery.Compile(,那么它将更改 LINQ to SQL 对布尔测试的翻译。 很好的输入,不幸的是我不能总是使用 Compile()。但我会在以后的项目中记住这一点,谢谢!

以上是关于与布尔值 false 进行比较时,如何防止 Linq2Sql 否定位列?的主要内容,如果未能解决你的问题,请参考以下文章

js ==和+

== 检查布尔值是不是完全相等? - 爪哇

隐式转换为布尔值并与布尔文字进行比较

==与===

如何对相同布尔值的块进行分组?

JPQL:CASE WHEN 中的布尔表达式何时需要与 TRUE/FALSE 进行显式比较?