本地序列不能在查询运算符的 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() 运算符除外的主要内容,如果未能解决你的问题,请参考以下文章