StartsWith с любой строкой из списка в запрос SQL с LINQ и Entity Framework

Я могу получить объекты из EF с таким запросом:

apples = apples.Where(a => a.Sort.Name.StartsWith("Gold"))

но мне интересно, возможно ли использовать список строк вместо одной строки? Я уже пытался сделать это так:

List<string> list = {...}

apples = apples.Where(a => list.Any(x => a.Sort.Name.StartsWith(x)))

но это дает мне странную ошибку:

System.ArgumentOutOfRangeException: указанный аргумент находится вне диапазона допустимых значений. (Параметр «индекс») в System.Linq.Expressions.InstanceMethodCallExpression1.GetArgument (индекс Int32) в Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionVisitors.NpgsqlSqlTranslatingExpressionVisitor.VisitLikeAnyAll (выражение SubQueryExpression) в Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionVisitors.NpgsqlSqlTranslatingExpressionVisitor.VisitSubQuery (выражение SubQueryExpression) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.SqlTranslatingExpressionVisitor.Visit (выражение выражения) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.SqlTranslatingExpressionVisitor.VisitBinary (выражение BinaryExpression) в Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionVisitors.NpgsqlSqlTranslatingExpressionVisitor.VisitBinary (выражение BinaryExpression) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.SqlTranslatingExpressionVisitor.Visit (выражение выражения) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.SqlTranslatingExpressionVisitor.VisitBinary (выражение BinaryExpression) в Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionVisitors.NpgsqlSqlTranslatingExpressionVisitor.VisitBinary (выражение BinaryExpression) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.SqlTranslatingExpressionVisitor.Visit (выражение выражения) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.SqlTranslatingExpressionVisitor.VisitBinary (выражение BinaryExpression) в Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionVisitors.NpgsqlSqlTranslatingExpressionVisitor.VisitBinary (выражение BinaryExpression) в Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.SqlTranslatingExpressionVisitor.Visit (выражение выражения) в Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, индекс Int32) в Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection1 bodyClauses, QueryModel queryModel) at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor[TResult](QueryModel queryModel) at Microsoft.EntityFrameworkCore.Storage.Database.CompileAsyncQuery[TResult](QueryModel queryModel) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQueryCore[TResult](Expression query, IQueryModelGenerator queryModelGenerator, IDatabase database) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass22_01.b__0() в Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1.System.Collections.Generic.IAsyncEnumerable.GetEnumerator() в System.Linq.AsyncEnumerable.Aggregate_[TSource,TAccumulate,TResult](накопитель IAsyncEnumerable1 source, TAccumulate seed, Func3, Func`2 resultSelector, CancellationToken CancellationToken) в D:\a\1\s\Ix.NET\Source\System.Interactive.Async \Aggregate.cs:строка 118 в {мой проект}

Что вы имеете в виду под a.Sort? Вы сортируете одно яблоко?

Steve 23.12.2020 19:22

Сорт — это объект, есть таблица со всеми сортами, поэтому у каждого яблока есть сорт и у каждого сорта есть имя. Мне просто нужно выбрать только яблоки из базы данных, имена которых начинаются с любой строки из списка

Mateech 23.12.2020 19:37

Вам нужно указать, какой LINQ to EF вы используете: EF 6.x, EF Core 2.0/2.1/3.x/5.x?

NetMage 23.12.2020 21:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
899
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Не смог получить ту же ошибку, что и вы (только что получил неудачный перевод, поэтому было бы здорово, если бы вы могли добавить минимальный воспроизводимый пример), у меня работало с использованием EF.Functions.ILike (с последним пакетом npgsql):

List<string> list = new() {"a%", "b%"};
var result = ctx.Apples
    .Where(c => list.Any(xx => EF.Functions.ILike(c.Sort.Name, xx)))
    .ToList();

Насколько я вижу, поддержка использования StartsWith с локальной коллекцией на данный момент не реализована (на основании этого PR и этого комментария), только EF.Functions.Like и EF.Functions.ILike.

Если вы хотите использовать LINQKit, вы можете создать методы расширения для построения выражений из локальных коллекций:

// searchTerms - IEnumerable<TSearch> where one must match for a row
// testFne(row,searchTerm) - test one of searchTerms against a row
// r => searchTerms.Any(s => testFne(r,s))
public static Expression<Func<T, bool>> AnyIs<T, TSearch>(this IEnumerable<TSearch> searchTerms, Expression<Func<T, TSearch, bool>> testFne) {
    var pred = PredicateBuilder.New<T>();
    foreach (var s in searchTerms)
        pred = pred.Or(r => testFne.Invoke(r, s));

    return pred;
}

// searchTerms - IEnumerable<TSearch> where one must match for a row
// testFne(row,searchTerm) - test one of searchTerms against a row
// dbq.Where(r => searchTerms.Any(s => testFne(r,s)))
public static IQueryable<T> WhereAny<T,TSearch>(this IQueryable<T> dbq, IEnumerable<TSearch> searchTerms, Expression<Func<T, TSearch, bool>> testFne) =>
    dbq.AsExpandable().Where(searchTerms.AnyIs(testFne));

Затем вы можете использовать их с вашим запросом:

List<string> list = {...}

apples = apples.WhereAny(list, (a,s) => a.Sort.Name.StartsWith(s));

Конечно, вы также можете создать свой собственный мини-LINQKit для выполнения той же задачи (хотя это не совсем так).

Другие вопросы по теме