C# 为什么在执行ToList()时LINQ to SQL查询会中断?

C# 为什么在执行ToList()时LINQ to SQL查询会中断?,c#,linq-to-sql,C#,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

最初,我用如下代码合并了两组结果:

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是空的。在做了ToList之后,它不再合并结果。我检查了updatedList1,并使myMethod始终返回true,因此本质上问题来自于使用ToList

我知道这可能与延期执行有关,但我不知道该怎么做。应该完全一样


有人有什么建议吗?

因为ToList返回的是IEnumerable,而IEnumerable不是IQueryable

澄清:


使用LINQtoSQL您隐式地使用了IQueryable,所以这些选择、连接和排序都被转换为SQL并在DB服务器上执行。但是,将updatedList1转换为List会阻止linq2sql将整个语句转换为SQL查询,并且它的语句会像在普通Linq中一样逐个执行。它不仅可能会引入一些错误,比如上面的答案中提到的NullReferenceException,而且它的效率比纯linq2sql表达式低得多。

因为ToList返回的是IEnumerable,而IEnumerable不是IQueryable

澄清:

使用LINQtoSQL您隐式地使用了IQueryable,所以这些选择、连接和排序都被转换为SQL并在DB服务器上执行。但是,将updatedList1转换为List会阻止linq2sql将整个语句转换为SQL查询,并且它的语句会像在普通Linq中一样逐个执行。它不仅可能会引入一些错误,如上面回答中提到的NullReferenceException,而且它的效率远远低于纯linq2sql表达式。

调用fishcakes.DefaultIfEmpty可以返回包含null的集合

如果调用.ToList,所有当前结果都将复制到本地.Net对象,并且.ToList之后的所有命令都将在程序中执行

如果您对.Net集合执行查询,则尝试调用null.ranking-这会引发NullReferenceException。同时,SQLServer上的执行不会抛出异常,因为在SQL中,请求null的子属性是可以的,它只会返回null

为了防止示例中出现异常:您可以筛选排名等于null的项,或者替换

orderby b.ranking 
对于这种情况,我假设排名是int

物化价值也是如此。例如,假设该项目可能有类别,也可能没有:

// 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?这是不需要的。不要相信

调用fishcakes.DefaultIfEmpty可以返回包含null的集合

如果调用.ToList,所有当前结果都将复制到本地.Net对象,并且.ToList之后的所有命令都将在程序中执行

如果您对.Net集合执行查询,则尝试调用null.ranking-这会引发NullReferenceException。同时,SQLServer上的执行不会抛出异常,因为在SQL中,请求null的子属性是可以的,它只会返回null

为了防止示例中出现异常:您可以筛选排名等于null的项,或者替换

orderby b.ranking 
对于这种情况,我假设排名是int

物化价值也是如此。例如,假设该项目可能有类别,也可能没有:

// 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?这是不需要的。不要相信

因为您正试图加入两个不同的不兼容类型。如果您使用list2并对其执行类似的.ToList操作,这将缓解症状。

因为您正试图加入两个不同的不兼容类型。如果您使用list2并对其执行类似的.ToList操作,这将缓解症状。

连接到类似于SQL中的左内部连接。因此,fishcakes对于某些a可能为空,因此fishcakes.DefaultIfEmtpy对于某些a可能返回null 试一试

联接到类似于SQL中的左内部联接。因此,fishcakes对于某些a可能为空,因此fishcakes.DefaultIfEmtpy对于某些a可能返回null 试一试


试着找到解决方案,记住这一点,你可以加入一个内存中的集合和一个遥远的集合!试着找到解决方案,记住这一点,你可以加入一个内存中的集合和一个遥远的集合!他想用哪种手术?我忘了怎么从。。。哪里select转换为LINQ方法调用。你当然可以打电话。名单上的什么地方。@Robert Harvey你说得对。我对我的回答做了一些澄清。他想用哪个IQueryable操作?我忘了怎么从。。。哪里select转换为LINQ方法调用。你当然可以打电话。名单上的什么地方。@Robert Harvey r 是的,你是。我对我的回答作了一些澄清。