2014-02-08 113 views
10

我有一個實體Person,其中包含與其關聯的位置列表。我需要查詢個人表,並從位置列表(標準)中獲取所有至少有一個位置的人。下面的作品,但效率非常低:檢查列表是否包含來自EntityFramework中其他列表的項目

var searchIds = new List<int>{1,2,3,4,5}; 
var result = persons.Where(p => p.Locations.Any(l => searchIds.Any(id => l.Id == id))); 

這對小名單(比如5-10 searchIds和5-10位置的人能正常工作的問題是,有些人可能有100個地點和搜索即可。當我試圖執行上面的EF時,實際上產生了2000多條SQL語句,並且因爲嵌套過於深入而失敗了,雖然嵌套本身已經是一個問題,即使它可以工作, d仍然不會發生在2000+ SQL語句中

注意:真正的代碼還包括多層次和父子關係,但我確實設法只用id來代替這個相當平坦的結構,而不是的福ll objects

在EF中完成此操作的最佳方法是什麼?

+0

獲得2000+ sql時,您傳遞了多少個ID? – ivowiblo

回答

4

嘗試切換到連接的,而不是做一個龐大的數據包括:

var searchIds = new List<int>{1,2,3,4,5}; 
var results = (from p in persons 
       join l in Location on p.PersonId equals l.PersonId 
       where searchIds.Contains(l.Id) 
       select p).Distinct().ToList(); 

顯然修復這條線,以配合您的類和/或加入財產。

join l in Location on p.PersonId equals l.PersonId 

我期望生成一個更友好的執行計劃。

+0

我與你在ORM上,所以這將是一個快速討論:-)不幸的是,我不能使用連接,因爲我沒有位置集(使用通用儲存庫)。儘管我發現'searchIds.Contains(l.Id)'比'searchIds.Any(id => l.Id == id)好很多。低至約70行的SQL,不超過但超過2000+ – Kenneth

+0

@Kenneth如果你能看到Person類中的'Locations'屬性,我不明白你爲什麼不能直接查詢這個類。也許我沒有正確理解這種情況。無論如何,我祝你好運。 – Timeout

+0

那麼,我只能直接訪問一個EntitySet(Persons)。其餘的應該是通過這個班級間接查詢的。據推測,EF處理連接並找出最佳執行路徑。據說...無論如何,這些包含似乎是最重要的部分。感謝您的幫助 – Kenneth

29

我會建議:

var searchIds = new List<int>{1,2,3,4,5}; 
var result = persons.Where(p => p.Locations.Any(l => searachIds.Contains(l.Id))); 

Contains將被轉換爲IN聲明。

請記住,id列表進入sql語句。如果你的ID列表很大,那麼你最終會得到一個巨大的查詢。

相關問題