Как использовать условие Linq where, чтобы проверить, содержит ли список строк какую-либо строку

#asp.net #list #entity-framework #linq #asp.net-core

Вопрос:

У меня есть запрос LINQ, подобный этому:

 var data = from user in _context.Users
           select new
           {
               UserId = user.Id,
               Username = user.UserName,
               RoleNames = (from userRole in _context.UserRoles
                            join role in _context.Roles on userRole.RoleId
                            equals role.Id
                            where userRole.UserId == user.Id
                            select role.Name).ToList()
           };

if (!string.IsNullOrEmpty(searchText))
    data = data.Where(x => x.Username.Contains(searchText) || x.RoleNames.Any(r => r.Contains(searchText)));
 

В результате получается что-то вроде этого:

 User Id | Username      | RoleNames
1       | Matt          | [User, Admin]
2       | Jennifer      | [User]
3       | John          | []
 

Но в

x.Имена ролей.Любой(r => r.Содержит(поисковый текст))

не работает, это вызывает исключение InvalidOperationException: не удалось перевести выражение LINQ’…’.

Я хочу ввести текст поиска для поиска столбцов «Имя пользователя» и «Имена ролей». Например, если я передам searchText = «Джен», он вернет идентификатор пользователя 2, а если я передам searchText = «пользователь», он вернет идентификатор пользователя 1 и 2.

Любая помощь будет признательна.

Комментарии:

1. У вас есть навигационная собственность User.Roles или что-то в этом роде?

2. Я предполагаю , что Users это непросто IEnumerable , и это _context DbContext так, и вы используете ORM, подобный Entity Framework. Проблема в том, что ваш ORM не знает, как перевести ваше лямбда-выражение в запрос базы данных, так что на самом деле это не проблема Linq.

3. Какой LINQ вы используете: LINQ для объектов / SQL / EF 6.x / EF Core 2.0 / 2.1 / 3.x / 5.x / 6.x? Какой поставщик баз данных?

4. Используя LinqKit , вы можете использовать Конструктор предикатов для создания выражения, которое можно перевести.

5. @NetMage, здесь ничто не может помочь. Пользовательская проекция затрудняет повторное использование коллекций в предикатах.

Ответ №1:

Хотя теоретически это условие можно перевести в SQL, ваша базовая версия EF этого не поддерживает. Подумайте о том, чтобы создать фильтр перед определением пользовательской проекции:

 var users = _context.Users.AsQueryable();

if (!string.IsNullOrEmpty(searchText))
    users = users.Where(x => x.Username.Contains(searchText) || x.Roles.Any(r => r.Contains(searchText)));

var data = 
    from user in users
    select new
    {
        UserId = user.Id,
        Username = user.UserName,
        RoleNames = (from userRole in _context.UserRoles
                    join role in _context.Roles on userRole.RoleId
                    equals role.Id
                    where userRole.UserId == user.Id
                    select role.Name).ToList()
    };
 

Ответ №2:

Возможно, это не тот ответ, который вам нужен сейчас, но вы, вероятно, оглянетесь назад и увидите, что это правильный ответ позже.

Ваш ORM (вероятно, Entity Framework) не может перевести выражения Linq в запрос. Если в вашем проекте будет небольшая база данных, и вам не нужно, чтобы ваши запросы хорошо выполнялись, измените свое выражение так, чтобы ORM мог генерировать функционирующий, хотя и неоптимальный, запрос.

Если данные будут важной частью вашего проекта, переключитесь на легкий ORM, такой как Dapper, и изучите язык запросов вашей базы данных. Пишите оптимальные, параметризованные запросы на этом языке запросов и получайте долгосрочные преимущества.