如果不支持包含,您如何在 LINQ to Entities(实体框架)中执行 SQL 样式的“IN”语句?

Posted

技术标签:

【中文标题】如果不支持包含,您如何在 LINQ to Entities(实体框架)中执行 SQL 样式的“IN”语句?【英文标题】:How do you do a SQL style 'IN' statement in LINQ to Entities (Entity Framework) if Contains isn't supported? 【发布时间】:2010-09-24 14:57:48 【问题描述】:

我正在使用 LINQ to Entities(不是 LINQ to SQL),但在创建“IN”样式查询时遇到了问题。这是我目前的查询:

var items = db.InventoryItem
                .Include("Kind")
                .Include("PropertyValues")
                .Include("PropertyValues.KindProperty")
                .Where(itm => valueIds.Contains(itm.ID)).ToList<InventoryItem>();

但是,当我这样做时,会引发以下异常:

LINQ to Entities 无法识别方法 'Boolean Contains(Int64)' 方法,并且该方法无法转换为存储表达式。

有人对此有解决方法或其他解决方案吗?

【问题讨论】:

valueIds的类型是什么? 【参考方案1】:

你需要使用这个:

.Where(string.Format("it.ID in 0", string.Join(",", valueIds.ToArray())));

或动态构造 WHERE 部分,如 this 帖子中的。

附注- 信息已更新,此答案更新如下以保持相关性:

引用的链接包含以下更新:

...在 EF4 中,我们添加了对的支持 包含方法和至少在这个 collection-valued 的具体情况 参数。所以这种 代码现在可以开箱即用 而且没有必要使用任何 附加表达式构建方法:

var statusesToFind = new List<int> 1, 2, 3, 4;
var foos = from foo in myEntities.Foos
           where statusesToFind.Contains(foo.Status)
           select foo;

【讨论】:

我注意到,即使将 where 作为字符串传递,IN 也会被转换为许多 OR 语句.. @liggett78 由于自定义 ORM 不支持 .Contains.Any,我现在面临这种情况。我正在尝试实现第一个解决方案,但我不确定它是如何工作的 - .Where 子句如何接受非函数参数?【参考方案2】:

在某些情况下,您可以使用 Linq 的 Any 扩展方法:

var userIds = new[]  1, 2, 3 ;

from u in Users
     where userIds.Any(i => i==u.Id)
     select u;

在这种情况下生成的 SQL 看起来很奇怪,但与许多 Linq-to-Entities 生成的 SQL 一样,它对人类来说可能过于冗长,但在实践中运行得很快。

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[DisplayName] AS [DisplayName], 
FROM [dbo].[Users] AS [Extent1]
WHERE  EXISTS (SELECT 
    1 AS [C1]
    FROM  (SELECT 
        [UnionAll1].[C1] AS [C1]
        FROM  (SELECT 
            1 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
        UNION ALL
            SELECT 
            2 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
    UNION ALL
        SELECT 
        3 AS [C1]
        FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
    WHERE [UnionAll2].[C1] = [Extent1].[Id]
)

【讨论】:

【参考方案3】:

正如 Diego B Vega 在 this post(第二个答案)中提到的,Contains 现在应该可以在 EF4 中使用。

【讨论】:

【参考方案4】:

我的解决方法是将实体结果转换为应用 Contains() 的列表和 之后

例子:

var items = db.InventoryItem
                .Include("Kind")
                .Include("PropertyValues")
                .Include("PropertyValues.KindProperty")
                .ToList()
                .Where(itm => valueIds.Contains(itm.ID));

【讨论】:

太糟糕了,有时我真的很讨厌 EF 让你跳过去做事。但它适用,只是在代码中看起来很糟糕。谢谢 事实上,这种“解决方法”从数据库中获取所有数据并在 C# 中对其进行过滤。如果您有大量数据,它会有效地降低性能。 -1:您不想在应用附加过滤器之前对集合进行水合。

以上是关于如果不支持包含,您如何在 LINQ to Entities(实体框架)中执行 SQL 样式的“IN”语句?的主要内容,如果未能解决你的问题,请参考以下文章

不支持 Linq-to-EF DateTime.ToLocalTime

Linq to EF 系统不支持异常 System.NotSupportedException

LINQ to SQL 或任何其他启用了 LINQ 的 ORM 是不是支持许多关联过滤?

如何修复 ApplicationUserManager 中的“LINQ to Entities 中不支持指定的类型成员‘UserId’”

.AsExpandable 在 Linq to Entity

如何在LINQ-To-SQL中排除Contex.InsertOnSubmit()上的用户定义字段?