2010-12-03 74 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. } 
相关问题