【问题标题】:EF Core 3.1 - how to do filtering based on parameters?EF Core 3.1 - 如何根据参数进行过滤?
【发布时间】:2020-01-13 10:05:08
【问题描述】:

在 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(我假设您无法在 Select 之后添加 Where)。

如果我尝试在过滤后添加Select,编译器会告诉我他无法将IQueryable<BusinessUnit> 转换为IQueryable<BuViewModel>

如果我尝试显式声明IQueryable<BuViewModel> query = ...,我必须在Where 子句之前写Select(这不起作用)。

这里最好的方法是什么?

【问题讨论】:

  • 试着把 Select 移到最后,EF 会理解你的 where 子句。
  • 试过了,不行,因为它和我声明的类型不同
  • 尝试类似 var query = context.BusinessUnits.AsQueryable();然后您可以使用此 Queryable 再次查询。
  • 您确定在 2.2 中它在 SQL 中运行查询,而不仅仅是将所有数据转储到内存中并在那里运行吗?我看不出任何 LINQ to SQL 引擎能够将 Select 转换为 SQL。
  • @Jimbot,我试过了

标签: asp.net-core entity-framework-core ef-core-3.1


【解决方案1】:

问题从这一行开始。 IQueryable 构造一个 SQL 查询,因此:

   .Select(x => new BUViewModel(x))

Iqueryable 不能调用构造函数。所以要手动修复它。

.Select(x=> new BUViewModel(){
               Id = x.Id,
               Name = x.Name // etc

            })

但是为什么构造函数不起作用?因为你可以在构造函数中编写任何你想要的代码。 EF 将无法将其转换为 SQL 查询。假设您可以编写这样的构造函数。

public BUViewModel(int id){
    var apiToken = _serviceCallApi(id);
}

上面的例子在构造对象时调用了一个api(这只是一个例子)。不可能将此逻辑转换为查询。有像 automapper 这样的工具可以自动映射实体。

我的猜测是您处理的不是 IQueryable,而是 IEnumerable。这是不正确的,因为您希望 SQL 为您过滤数据。不要将所有内容都加载到内存中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 1970-01-01
    • 2019-04-02
    • 2021-01-27
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    相关资源
    最近更新 更多