日期:2014-05-20  浏览次数:21006 次

关于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);
}