EF Core 3.1 - как сделать фильтрацию по параметрам?

В 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 фильтровал данные для вас. Не загружать все в память.


Есть идеи?

10000