c# - Entity Framework ,LINQ : can't use Any with StartsWith?

标签 c# .net linq entity-framework-core

我有一个简单的 Entity Framework LINQ 查询。目标是找到所有以 A、B 或 C 开头的载体:

var letters = new List<string>() { "A", "B", "C" }; // Dynamic, can be many
var results = db.Carriers.AsNoTracking()
    .Where(c => letters.Any(val => c.Name.StartsWith(val)))
    .ToList();
我得到

System.InvalidOperationException: 'The LINQ expression 'DbSet .Where(c => __letters_0 .Any(val => val == "" || c.Name != null && val != null && c.Name.StartsWith(val)))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'


没有办法做到这一点吗?

最佳答案

在 Entity Framework 6 中,此查询可以正常运行。 EF6 支持 StartsWith 的 SQL 转换并且它支持在查询表达式中使用本地序列( letters )。
EF core 3(问题中的版本如异常消息所示)也支持StartsWith的SQL翻译。 .这里的问题(另一个答案完全忽略了)是本地序列的使用方式不受支持。像这样的查询...

var results = db.Carriers.AsNoTracking()
    .Where(c => letters.Contains(c.Name))
    .ToList();
...将得到支持,因为 letters可以简单地翻译成 IN条款。但当然,这是一个完全不同的查询。
使用 letters.Any需要 EF 转换 letters变成可以在 SQL 中加入的“东西”。 EF6 通过在 SQL 查询中构建结果集来做到这一点:
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM  (SELECT 
            N'A' AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
        UNION ALL
            SELECT 
            N'B' AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]
        UNION ALL
            SELECT 
            N'C' AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
        WHERE ( CAST(CHARINDEX([UnionAll2].[C1], [Extent1].[Name]) AS int)) = 1
哪个有效,但根本无法扩展。 EF core 3 不支持它,并且没有其他答案中建议的简单解决方法。
一种可能的解决方法是使用 || 构建谓词(或)谓词,例如:
var pred = letters.Aggregate(PredicateBuilder.False<Carrier>(), 
    (p,x) => p = p.Or(c => c.Name.StartsWith(x)));
var results = db.Carriers.AsNoTracking()
    .Where(pred)
    .ToList();
哪里PredicateBuilder是一个谓词构建器,如 Linqkit 或 this one .但是这种方法也不是可扩展的。 EF 为 letters 中的每个条目创建一个参数,因此您可能会在 Sql Server 中达到 2100 个参数的阈值。

关于c# - Entity Framework ,LINQ : can't use Any with StartsWith?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63732025/

相关文章:

c# - 在 WPF 中序列化 BitmapImage

c# - 使用 <%@ Page Async ="true"异步返回数据后对 GridView 进行分页

c# - 在 C# 中获取具有 2 位数年份的特定于文化的日期

c# - 为什么 ServerVariable ["REMOTE_ADDR"] 返回服务器 IP?

c# - Entity Framework 为分页查询生成低效的 SQL

ASP.NET Web API返回可查询的DTO?

c# - OpenXml-SDK:如何将 FontFamily/Size 应用于 [TextPlain] 类型的 AltChunk

c# - FluentValidation 使用手动验证的隐式子验证

c# - NSubstitute - 模拟在返回任务的方法中抛出异常

c# - 在 C# 中打印数组的所有内容