2010-12-03 62 views
1

本來我是合併兩組結果有這樣的代碼:當我做ToList()時,爲什麼這個LINQ to SQL查詢會中斷?

var list1 = from a in IDataSourceObject 
      blahblah 
      select a; 

var list2 = from a in IDataSourceObject2 
      blahblah 
      select a;  

var joinedlist = from a in list1 
       join b in list2 on a.id = b.id 
       into fishcakes 
       from b in fishcakes.DefaultIfEmpty() 
       orderby b.ranking 
       select new { blah=cakes, etc. } 

這用來做工精細,但後來我想過濾列表1多一點,所以我這樣做:

var list1 = from a in IDataSourceObject 
      blahblah 
      select a; 

// ToList required because im calling a method in my code 
var updatedList1 = from a in list1.ToList() 
        where myMethod(somestuff) == true 
        select a; 

var list2 = from a in IDataSourceObject2 
      blahblah 
      select a;  

var joinedlist = from a in updatedList1 
       join b in list2 on a.id = b.id 
       into fishcakes 
       from b in fishcakes.DefaultIfEmpty() 
       orderby b.ranking 
       select new { blah=cakes, etc. } 

但是我收到一個錯誤,基本上說OrderBy b.ranking爲null。在完成ToList之後,它不再合併結果。我已經檢查updatedList1,並且我讓myMethod總是返回true,所以本質上來自使用ToList()的問題。

我明白這可能與延遲執行有關,但我不知道怎麼做。它應該完全一樣。

有沒有人有任何建議?

+0

試圖找到考慮到這一點,你與遠方的一個連接的記憶中珍藏的解決方案! – 2010-12-03 16:05:02

回答

6

打電話給fishcakes.DefaultIfEmpty()可以返回集合null在裏面。

如果您調用.ToList(),則所有當前結果都將複製到本地(.Net)對象,並且在您的程序中將執行.ToList()之後的所有命令。

如果您對.Net集合執行查詢,然後嘗試撥打null.ranking - 其中拋出NullReferenceException。同時SQL Server上的執行不會拋出異常,因爲在SQL中,可以要求子屬性爲null(它只會返回null)。

要防止在你的榜樣例外:您可以過濾項,有ranking等於null,或更換

orderby b.ranking 

到這樣的事情(我假設ranking爲int)

orderby b != null ? b.ranking : -1 


與物化值相同的情況也是如此。例如(假定,即Item可能有Category,或可能沒有):

// this will work, because it's executed on SQL-side 
db.Items 
     .Select(x=>new { CatId = (int?)x.Category.Id, x.Id}) 
     .ToList(); 

// this will throw NullRefException, because it's executed against collection in .Net environment, not on SQL Server. 
db.Items 
     .ToList() 
     .Select(x=>new { CatId = (int?)x.Category.Id, x.Id}); 

PS:如果你使用ReSharper的,它會抱怨在第一個例子中,該鑄造int?是沒有必要的。不要相信它! )

0

因爲ToList()返回IEnumerable的,這是不是IQueryable的

澄清:

使用LINQ你使用隱式IQueryable的,所以那些選擇,連接和排序,以SQL被轉換成SQL和執行在DB服務器上。但是,將updatedList1轉換爲List可以防止linq2sql將整個語句翻譯爲SQL查詢,並且它的語句正在逐個執行,就像在正常的Linq中一樣。它不僅可能引入一些錯誤(如上面的答案中提到的NullReferenceException),而且它比「純」linq2sql表達式效率低得多。

+1

這有點含糊。 – 2010-12-03 16:02:58

0

因爲您試圖加入2種不同(不兼容)的類型。如果您使用list2並對其執行類似的.ToList()操作,則應該緩解症狀。

2

join into類似於SQL中的左內連接。所以,魚餅可以是空的一些a,因此fishcakes.DefaultIfEmtpy()可以返回null一段a 嘗試

var joinedlist = from a in updatedList1 
       join b in list2 on a.id = b.id 
       into fishcakes 
       from b in fishcakes 
       where b != null 
       orderby b.ranking 
       select new { blah=cakes, etc. } 
相關問題