最初我用这样的代码合并了两组结果:
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 :(得分: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?
。不要相信! )
答案 1 :(得分:2)
join into
类似于SQL中的左内连接。因此,对于某些a
,fishcakes可能为空,因此fishcakes.DefaultIfEmtpy()
可能会为某些a
返回null
尝试
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. }
答案 2 :(得分:0)
因为ToList()返回IEnumerable,这不是IQueryable
澄清:
使用Linq to SQL,您隐式使用IQueryable,因此这些选择,连接和排序将转换为SQL并在DB服务器上执行。但是,将updatedList1转换为List会阻止linq2sql将整个语句转换为SQL查询,并且其语句将逐个执行,就像在普通Linq中一样。它不仅可能引入一些错误(如上面的答案中提到的NullReferenceException),而且它的效率远低于“纯”linq2sql表达式。
答案 3 :(得分:0)
因为您尝试加入两种不同(不兼容)的类型。如果您使用list2并对其执行类似的.ToList()
操作,这应该可以缓解症状。