#c# #.net-core #entity-framework-core #ef-core-3.1
#c# #.net-core #entity-framework-core #ef-core-3.1
Вопрос:
У меня есть Person
модель с Gender
папкой перечисления, которая хранится в виде строки в базе данных. Я хочу сделать запрос для фильтрации данных по подстроке пола. Например, если query.SearchLike
это "Fe"
или "em"
, я бы хотел вернуть всех лиц женского пола. К сожалению, приведенный ниже код выдает исключение.
builder.Entity<Person>().Property(x => x.Gender).HasConversion<string>();
public async Task<IList<Person>> ListAsync(PersonsQuery query)
{
IQueryable<Person> queryable = _context.Persons.AsNoTracking();
return await queryable
.Where(x => x.Gender.ToString().Contains(query.SearchLike))
.ToListAsync();
}
Исключение:
Выражение LINQ ‘DbSetr n .Где(x => x.Пол.Не удалось перевести toString().Contains(__query_SearchLike_0))’. Либо перепишите запрос в форме, которая может быть переведена, либо переключитесь на оценку клиента явно, вставив вызов AsEnumerable() , AsAsyncEnumerable() , ToList() или ToListAsync() . См. https://go.microsoft.com/fwlink/?linkid=2101038 для получения дополнительной информации.
Комментарии:
1. что является исключением?
2. В этом проблема с преобразованиями. Они делают фильтрацию практически невозможной.
3. И что может быть практическим решением?
4. Сохраняйте
Gender
какint
вместо строки. Сопоставьте поиск с перечислением и найдите всеPerson
s, соответствующие любым значениям перечисления, соответствующим вашему поиску. Это тоже должно быть намного более производительным5. Почему вы выполняете преобразование? Просто определите свои перечисления как строковые свойства. Если вы хотите иметь строковые значения. в противном случае для повышения производительности и даже для других целей лучше хранить его в базе данных в виде целых чисел.
Ответ №1:
Насколько я понимаю, вы должны использовать функции, подобные EF. Попробуйте что-то вроде этого:
public async Task<IList<Person>> ListAsync(PersonsQuery query)
{
IQueryable<Person> queryable = _context.Persons.AsNoTracking();
return await queryable
.Where(x => EF.Functions.Like(x.Gender, "%" query.SearchLike "%")
.ToListAsync();
}
Комментарии:
1.
EF.Functions.Like()
ожидается два строковых параметра, но x.Gender является перечислением. Когда я вызываюx.Gender.ToString()
, то получаю исключение, в котором говорится: «Выражение LINQ не удалось перевести».
Ответ №2:
Я нашел решение. Сначала нужно привести перечисление к object
, а затем к string
.
public async Task<IList<Person>> ListAsync(PersonsQuery query)
{
IQueryable<Person> queryable = _context.Persons.AsNoTracking();
return await queryable
.Where(x => ((string)(object)x.Gender).Contains(query.SearchLike))
.ToListAsync();
}
Связанный вопрос в репозитории Github ядра EF.
Ответ №3:
Вы можете использовать FromSql
метод для выполнения необработанного оператора SQL
public async Task<IList<Person>> ListAsync(PersonsQuery query)
{
var param = $"%{query.SearchLike}%"
return await _context.Persons
.FromSql("SELECT * FROM Persons WHERE Gender LIKE {0}" , param)
.ToListAsync();
}