本地序列不能在查询运算符的 LINQ to SQL 实现中使用,但 Contains() 运算符除外

Posted

技术标签:

【中文标题】本地序列不能在查询运算符的 LINQ to SQL 实现中使用,但 Contains() 运算符除外【英文标题】:Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator 【发布时间】:2011-12-31 03:45:54 【问题描述】:

我在我的项目中使用 LINQ,我的代码是:

var SE = from c in Shop.Sections
                    join c1 in obj.SectionObjects on c.SectionId equals c1.SectionId
                    select c;

 dataGridView1.DataSource = SE;

但我在dataGridView1.DataSource = SE; 行中遇到了这个错误 错误信息是:

【问题讨论】:

将鼠标悬停在 Shop.Sections 上并告诉我们它的类型。然后将鼠标悬停在 obj.SectionObjects 上并告诉我们它的类型。 【参考方案1】:

您不能在 SQL 源和本地源之间使用 Join。您需要先将 SQL 数据导入内存,然后才能加入它们。在这种情况下,您并没有真正进行连接,因为您只从第一个集合中获取元素,您想要的是一个 select...where...selectid in 查询,您可以使用 Contains 方法获取。

 var SE = Shop.Sections.Where( s => obj.SectionObjects
                                       .Select( so => so.SectionId )
                                       .Contains( s.SectionId ))
                       .ToList();

翻译成

select * from Sections where sectionId in (...)

in 子句的值来自本地对象集合中的 id 列表。

【讨论】:

这并不完全正确。如果本地源先行,则可以使用连接。请参阅下面的答案。【参考方案2】:

您不能将本地源加入 SQL 源, 但你可以将 SQL 源加入本地,v.v.

var SE = from c1 in obj.SectionObjects
              join c in Shop.Sections on c1.SectionId equals c.SectionId
              select c;

换句话说,本地资源必须放在第一位

【讨论】:

这应该是公认的答案。在这种方法中,(除非我大错特错),不会枚举 SQL 源(因此避免了一些 DB 开销) 如果 db 表相当小,此解决方案有效。但是,它确实枚举了从数据库到内存的整个表(通过 SQL 跟踪验证)来进行比较。我们有一个复杂的多表“SQL 源到本地”场景,因此开始出现内存不足异常错误。使用包含的其他答案允许查询使用“IN”在 SQL Server 上运行,并且只提取相关记录。这些答案应该是公认的答案,尤其是对于较大的表格。【参考方案3】:

这应该在数据库端(使用IN)而不是在内存中工作和完成:

var SE = from c in Shop.Sections 
        where obj.SectionObjects.Select(z => z.SectionId).Contains(c.SectionId)
        select c; 

L2S Profiler 对这类事情非常有帮助 - 您可以比较我的解决方案和其他解决方案生成的不同 SQL。

【讨论】:

这段代码无效,错误是:错误1 'System.Data.Linq.EntitySet.Contains(Shop.SectionObject)'的最佳重载方法匹配有一些无效参数 是的,看起来 L2S 基本上已经死了 - nuget.org/packages/LinqToSqlProfiler 在数据库端比在内存中快得多!【参考方案4】:

var SE = from c in Shop.Sections.AsEnumerable().ToList() 在 c.SectionId 上的 obj.SectionObjects.AsEnumerable().ToList() 中加入 c1 等于 c1.SectionId 选择 c;

dataGridView1.DataSource = SE;

【讨论】:

以上是关于本地序列不能在查询运算符的 LINQ to SQL 实现中使用,但 Contains() 运算符除外的主要内容,如果未能解决你的问题,请参考以下文章

linq to sql select和where的区别

LINQ to SQL语句之Join

使用Linq to SQL加载DataGridView

为啥,当我在 WCF 服务中模拟时,当我尝试运行 LINQ to SQL 查询时,我的服务不能加载 System.Transactions?

AsEnumerable()对LINQ实体的影响是什么?

Linq To Sql Contains 参数数量最大不能超过 2100 怎么解决?