В ef core 2.2 я мог бы сделать следующее:
var query = _dbContext.BusinessUnits
.Include(a => a.Parent)
.Include(a => a.Region)
.AsNoTracking().Select(x => new BUViewModel(x));
if (!string.IsNullOrWhiteSpace(dto.Name))
{
query = query.Where(x => x.Name.ToLower().Contains(dto.Name.ToLower()));
}
if (dto.Level != null)
{
query = query.Where(x => x.Level == dto.Level);
}
if (dto.ParentId != null)
{
query = query.Where(x => x.ParentId == dto.ParentId);
}
Похоже, что 3.1 не может перевести это на SQL (я полагаю, вы не можете добавить Where
после Select
). Если я пытаюсь добавить Select
после фильтрации, компилятор говорит мне, что он не может преобразовать IQueryable<BusinessUnit>
в IQueryable<BuViewModel>
. Если я пытаюсь явно объявить IQueryable<BuViewModel> query = ...
, я должен написать предложения Select
before Where
(и это не будет работать). Каков наилучший подход здесь?
Всего 1 ответ
Проблема начинается с этой строки. IQueryable создает запрос SQL так:
.Select(x => new BUViewModel(x))
Iqueryable не может вызывать конструкторы. Итак, чтобы исправить это, сделайте это вручную.
.Select(x=> new BUViewModel(){
Id = x.Id,
Name = x.Name // etc
})
Но почему конструктор не работает? Потому что вы можете написать любой код в конструкторе. EF не сможет перевести на него SQL Query. Допустим, вы можете написать конструктор, как это.
public BUViewModel(int id){
var apiToken = _serviceCallApi(id);
}
Выше, например, вызывает API, когда он создает объект (это просто пример). Невозможно перевести эту логику в запрос. Есть такие инструменты, как automapper, которые могут автоматически отображать объекты.
Я думаю, просто вы имели дело не с IQueryable, а с IEnumarable. Что неверно, потому что вы хотите, чтобы SQL фильтровал данные для вас. Не загружать все в память.