2012-03-12 79 views
10

我有一個問題,建立一個相當沉重的LINQ查詢。基本上我有一種情況,我需要在循環中執行一個子查詢來過濾從數據庫返回的匹配數。實施例的代碼是在低於該循環:Linq multiple where queries

 foreach (Guid parent in parentAttributes) 
     { 
      var subQuery = from sc in db.tSearchIndexes 
          join a in db.tAttributes on sc.AttributeGUID equals a.GUID 
          join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID 
          where a.RelatedGUID == parent && userId == pc.CPSGUID        
          select sc.CPSGUID; 

      query = query.Where(x => subQuery.Contains(x.Id)); 
     } 

當我隨後調用ToList()的查詢變量似乎只有所述子查詢中的單獨一個已被執行,並與數據的一桶我留下我不需要。但是這種方法的工作原理:

 IList<Guid> temp = query.Select(x => x.Id).ToList(); 

     foreach (Guid parent in parentAttributes) 
     { 
      var subQuery = from sc in db.tSearchIndexes 
          join a in db.tAttributes on sc.AttributeGUID equals a.GUID 
          join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID 
          where a.RelatedGUID == parent && userId == pc.CPSGUID        
          select sc.CPSGUID; 

      temp = temp.Intersect(subQuery).ToList(); 
     } 

     query = query.Where(x => temp.Contains(x.Id)); 

不幸的是這種方法是討厭的,因爲它導致多個查詢到遠程數據庫,由此,如果我能得到它的工作只會導致一個命中的初步做法。有任何想法嗎?

回答

8

我認爲你正在碰到一個捕獲用於過濾的lambda表達式中的循環變量的特殊情況。也稱爲訪問修改的關閉錯誤。

嘗試這種情況:

​​

問題是捕獲在封閉的可變parent(該LINQ語法轉換爲),這會導致所有的subQuery下載到具有相同父ID來運行。

會發生什麼情況是編譯器生成一個類來存放委託和委託訪問的局部變量。編譯器爲每個循環重新使用該類的同一個實例;因此,一旦查詢執行完畢,所有Wheres都執行相同的parentGuid,即執行的最後一個。

聲明循環範圍內的parent使編譯器基本上使變量的副本,爲正確的值,被捕獲。

這可能有點難以理解,所以如果這是第一次打到你;我建議爲背景這兩篇文章和詳盡的解釋:

+0

+1如果你想了解這個概念的更多,在這裏看看飛碟雙向的答案,他引用的文章。 http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop – 2012-03-12 20:00:08

+0

@DMoses感謝,我加了一些鏈接,完全承認,我無法解釋這個優雅而精確的紳士Lippert和Skeet :-) – driis 2012-03-12 21:29:50

+0

謝謝你driis。像魅力一樣工作。你是一位聖人和一位學者先生。 – kh25 2012-03-13 09:48:44

0

也許這種方式?

var subQuery = from sc in db.tSearchIndexes 
       join a in db.tAttributes on sc.AttributeGUID equals a.GUID 
       join pc in db.tPeopleIndexes on a.GUID equals pc.AttributeGUID 
       where parentAttributes.Contains(a.RelatedGUID) && userId == pc.CPSGUID        
       select sc.CPSGUID; 
+0

感謝您的答覆k06a但上面的查詢嘗試(但不成功)做一些與你提出的查詢略有不同的事情。基本上我是通過所有的parentAttributes進行過濾,同時你可以通過任何方式進行過濾,這將返回一組更大的結果。 – kh25 2012-03-13 00:24:54