关于LinQ的动态Or查询.
代码如下
public static IQueryable<DataLib.T_DISPATCH> GetNeedReceive(List<int> hubID)
{
try
{
HUBDataDataContext db = new HUBDataDataContext();
var predicate = PredicateExtensions.False<T_DISPATCH>();
foreach (int h in hubID)
{
predicate = predicate.Or(c => c.ToHUBID == h);
}
var dispatch = db.T_DISPATCH.Where(predicate).Where(c => c.State == 3);
return dispatch;
}
catch (Exception ex)
{
_log.Error(ex.ToString());
return null;
}
}
这里使用的PredicateExtensions来自MS的论坛,在网上的资料也很多,应该都可以搜索到。
但是这段代码完全无法正常工作。
但只要把以下这段改为
foreach (int h in hubID)
{
int htemp=h;
predicate = predicate.Or(c => c.ToHUBID == htemp);
}
程序就运行正常了。
想问下这二者有什么区别吗?
我的环境为VS2008SP1+.NET3.5SP1,谢谢!
------解决方案--------------------关注,以前也是这么解决的一个linq的问题
------解决方案--------------------无法正常工作 是提示错误还是结果错误?
------解决方案--------------------我用vs2005,帮顶
------解决方案--------------------学习一下心东西。
------解决方案-------------------- 帮顶
------解决方案--------------------
首先要理解什么叫Deffered Execution,即延迟查询。
只有通过直接调用对象的 GetEnumerator 方法或使用foreach来枚举该对象时,才执行此方法表示的查询。
LINQ表达式即时返回值为一个对象,该对象存储执行操作所需的所有信息。
foreach (int h in hubID)
{
predicate = predicate.Or(c => c.ToHUBID == h);
}
中实际predicate保存了一个 h的引用,当后面执行查询的时候,这个h因为foreach的关系已经是最后一个值了
foreach (int h in hubID)
{
int htemp=h;
predicate = predicate.Or(c => c.ToHUBID == htemp);
}
中每次执行循环体都构造一个临时变量 htemp,最后当你执行查询的时候,predicate已经有5个htemp引用了
------解决方案--------------------
代码原先写的确实是没有办法执行,主要是延迟执行所引起的,就是你上面的代码predicate = predicate.Or(c => c.ToHUBID == h);
要等到foreach的时候才会执行,此时的h早就已经是 hubID的最后一个值了,所以不对
给楼主举个书上的例子你就明白了:
IEnumerable<char> query="Not what you might expect";
foreach(char vowel in "aeiou")
{
query=query.where(c=>c!=vowel);
}
foreach(char c in query) Console.Write(c);
输入的结果是:Not waht yo minght expect
出现了我们不想要的结果(只是删除了'u'),原因就是上面的第一个foreach代码翻译成了下面的代码:
IEnumerable<char> vowels="aeiou";
IEnumerable<char> rator=vowels.GetEnumerator();
char vowel;
while(rator.Next())
{
vowel=rator.Current;
query=query.where(c=>c!=vowel);
}
因为延迟执行(也就是到第二个foreach才执行query=query.where(c=>c!=vowel);),由于vowel是在while外面定义,所以到第二个foreach执行时,vowel已经为'u'了,所以出现了错误
这个时候像你一样添加一个临时变量就可以正确的执行:
foreach(char vowel in "aeiou")
{
char temp=vowel;
query=query.where(c=>c!=temp);
}