通过DataContext使用DB。
进行此类操作:
var flat = StavRealtyDb.TargetFlat
.Where(x => true || _some condition_).ToList();
因此,如果条件的第一部分是 true ,编译器应该跳过,对吧? 但它并没有发生。如果有.ToArray()。
,也会发生同样的问题但是,如果它最终不会像.ToList或.ToArray那样 - 编译器将跳过条件的第二部分。
有什么问题?这是正常的吗? :)
更新
好的,谢谢你的回答!我明白这是正常的。但问题是条件的第一部分包含:someobject == null;第二部分包含:someobject.Contains()。
.Where(x => someobject == null || someobject.Field.Contains(x.somefield))
所以当someobject == null时,我有 ArgumentNullException (我希望第一部分将返回true而第二部分将不会执行)。你能告诉我,我该如何解决这个问题?
P.S:实际上,.Where()表达式更复杂:
.Where(x=> (part1 || part 2) && (part1 || part2) && ......)
答案 0 :(得分:2)
您在[{1}}上Where
进行了IQueryable
而论证是Expression
而不是Func
http://msdn.microsoft.com/en-us/library/vstudio/bb535040%28v=vs.100%29.aspx
Expression
刚刚传递给基础Where
实现。
我发现这个主题很有趣,所以我创造了一个例子。假设我们有以下代码:
using System;
using System.Linq.Expressions;
namespace TestApplication
{
class CompilerTest
{
public void Test()
{
Func<bool> func = () => true || Foo();
Expression<Func<bool>> expr = () => true || Foo();
}
public static bool Foo()
{
return new Random().Next() % 2 == 0;
}
}
}
我们构建它(发布版本),反编译代码如下所示:
using System;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
namespace TestApplication
{
internal class CompilerTest
{
[CompilerGenerated]
private static Func<bool> CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1;
public CompilerTest()
{
base.\u002Ector();
}
public void Test()
{
if (CompilerTest.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1 == null)
{
// ISSUE: method pointer
CompilerTest.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1 = new Func<bool>((object) null, __methodptr(\u003CTest\u003Eb__0));
}
Func<bool> func = CompilerTest.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1;
(Expression<Func<bool>>) (() => true || CompilerTest.Foo());
}
public static bool Foo()
{
return new Random().Next() % 2 == 0;
}
[CompilerGenerated]
private static bool \u003CTest\u003Eb__0()
{
return true;
}
}
}
如果我们隐藏编译器生成的代码(dotPeek选项),它看起来像这样:
using System;
using System.Linq.Expressions;
namespace TestApplication
{
internal class CompilerTest
{
public void Test()
{
Func<bool> func = (Func<bool>) (() => true);
(Expression<Func<bool>>) (() => true || CompilerTest.Foo());
}
public static bool Foo()
{
return new Random().Next() % 2 == 0;
}
}
}
正如我们所看到的,lambda 中指定的Func代码是优化的(如果编译器对其进行优化,这是真正的问题)。表达式中指定的代码显然没有被优化(因为它是一个表达式,因此从编译器的角度来看,此时没有任何优化)。
答案 1 :(得分:1)
到目前为止,答案触及了一些可以发挥作用的问题,但并未涵盖整体情况。此外,第二个条件是Contains
语句是必不可少的信息。所以,让我们说核心陈述是
StavRealtyDb.TargetFlat.Where(x => true || someList.Contains(x.Id))
如上所述,整个LINQ语句是Expression
,因此编译器不应用任何优化。如果一切顺利的话 -
var flat
。在这个事件过程中,第二个谓词总是由.Net运行时读,而不管它前面有多少谓词,但如果数据库评估查询优化器找到理由这样做。
现在出了点问题:someList
是null
。现在整个过程在第3步停止。查询提供程序尝试读取someList
(以便将其转换为IN
子句)。但是,当然,这会因为空引用而失败。
因此,您必须确保someList
永远不会为空(可能是空列表),或者您可以撰写Where
条件:仅当someList
不是{0}时null,您包含Contains
谓词。
答案 2 :(得分:0)
我认为这对于Linq Providers来说是正常的和按照设计的。在这种情况下,Linq Provider旨在获取Where表达式并将其转换为Sql并在Sql Server上执行它。
答案 3 :(得分:0)
Where()
将返回IQueryable<>
,您可以将其视为准备执行的查询。但是,Where()
中只有内置,只要需要实际数据,它就会执行 - 在这种情况下,调用{{1}时}。查询将保持OR,因此它是完全正常的行为,它不会被短路,因为它根本不在ToList()
内执行。
如果您想更好地理解它,请尝试将其拆分并在Where()
处设置断点。
Where()
在调试时将鼠标悬停在var query = StavRealtyDb.TargetFlat.Where(x => true || _some condition_);
var actualData = query.ToList();
上时,您会发现它是一个像
query
调用SELECT `Extent1`....
后,您会注意到数据已从数据库中检索出来并放入ToList()
。