Mar*_*ark 47 c# sql-server entity-framework
我在搜索字符串字段时遇到了EF创建可怕查询的问题.它以懒惰程序员的风格产生了一个查询,包含空检查,强制扫描整个索引.
考虑以下查询.
查询1
var p1 = "x";
var r1 = ctx.Set<E>().FirstOrDefault(
subject =>
p1.Equals(subject.StringField));
Run Code Online (Sandbox Code Playgroud)查询2
const string p2 = "x";
var r2 = ctx.Set<E>().FirstOrDefault(
subject =>
p2.Equals(subject.StringField));
Run Code Online (Sandbox Code Playgroud)查询1生成
WHERE (('x' = [Extent2].[StringField]) OR (('x' IS NULL) AND ([Extent2].[StringField] IS NULL)))
Run Code Online (Sandbox Code Playgroud)
并在4秒内执行
查询2生成
WHERE (N'x' = [Extent2].[StringField])
Run Code Online (Sandbox Code Playgroud)
并在2毫秒内执行
有谁知道任何工作?(没有参数不能是const,因为它是由用户输入输入的,但不能为null.)
NB在分析时,两个查询都是由EF用sp_executesql编写的; 因为如果它们刚被执行,查询优化器将否定OR'x'IS NULL检查.
Bas*_*ili 36
设置UseDatabaseNullSemantics = true;
获取或设置一个值,该值指示在比较两个操作数时是否显示数据库空语义,这两个操作数都可能为空.默认值为false.例如(operand1 == operand2)将被翻译为:(operand1 = operand2)如果UseDatabaseNullSemantics分别为true(((operand1 = operand2)AND(NOT(operand1 IS NULL或operand2 IS NULL)))OR((operand1 IS) NULL)AND(operand2 IS NULL)))如果UseDatabaseNullSemantics为false.
WHERE operand1 = operand2
Run Code Online (Sandbox Code Playgroud)
你也可以从外部设置这个设置到你的dbContext实例,就像下面的代码示例一样,从我的角度来看(参见@GertArnold评论),这个apporach会更好,因为它不会改变默认的数据库行为或配置):
WHERE
(
(operand1 = operand2)
AND
(NOT (operand1 IS NULL OR operand2 IS NULL))
)
OR
(
(operand1 IS NULL)
AND
(operand2 IS NULL)
)
Run Code Online (Sandbox Code Playgroud)
您可以通过添加[Required]
StringField属性来解决此问题
public class Test
{
[Key]
public int Id { get; set; }
[Required]
public string Bar{ get; set; }
public string Foo { get; set; }
}
string p1 = "x";
var query1 = new Context().Tests.Where(F => p1.Equals(F.Bar));
var query2 = new Context().Tests.Where(F => p1.Equals(F.Foo));
Run Code Online (Sandbox Code Playgroud)
这是query1
{SELECT [Extent1].[Id] AS [Id],[Extent1].[Bar] AS [Bar],[Extent1].[Foo] AS [Foo] FROM [dbo].[Tests] AS [Extent1] WHERE @ p__linq__0 = [Extent1].[Bar]}
这是query2
{SELECT [Extent1].[Id] AS [Id],[Extent1].[Bar] AS [Bar],[Extent1].[Foo] AS [Foo] FROM [dbo].[Tests] AS [Extent1] WHERE (@ p__linq__0 = [Extent1].[Foo])OR((@ p__linq__0 IS NULL)AND([Extent1].[Bar2] IS NULL))}
归档时间: |
|
查看次数: |
4682 次 |
最近记录: |