#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, и изучите язык запросов вашей базы данных. Пишите оптимальные, параметризованные запросы на этом языке запросов и получайте долгосрочные преимущества.