将委托传递给EF Core中的linq查询

时间:2017-01-23 20:05:54

标签: c# .net entity-framework linq entity-framework-core

我有以下委托声明:

private Func<Employee, bool> _exclude;

然后我的代码中的其他地方将其值设置为:

_exclude = (subject) =>
  !subject.IsDeleted && subject.Location.Department.Company.GroupId.Equals(_groupId);

目标是在所有查询中重用过滤器。如果我要实现这样的员工实例,这样可以正常工作:

Employee theEmployee = db.Employees
    .Include(e=>e.Location)
    .ThenInclude(e => e.Department)
    .ThenInclude(e => e.Company)
    .Where(e => e.EmployeeId == EmployeeId && _exclude(e))
    .FirstOrDefault();

但是当我只想检索单个值时失败,例如EmployeeId:

string employeeId = db.Employees
    .Include(e=>e.Location)
    .ThenInclude(e => e.Department)
    .ThenInclude(e => e.Company)
    .Where(e => e.EmployeeId == EmployeeId && _exclude(e))
    .Select(e => e.EmployeeId)
    .FirstOrDefault();

上述操作无法在Func委托 _exclude 中产生NullReferenceException,因为subject.Location值为null,这意味着传递给委托的员工未按照Includes完全具体化。

当需要完全成熟的Employee但是投影查询失败时,成功实现Employee图的原因是什么,或者在这种情况下如何编写查询?

我正在使用EF Core

1 个答案:

答案 0 :(得分:4)

  

当需要完整的员工但投影查询失败时,成功实现员工图表的原因是什么?

在这两种情况下,_exclude(e)都没有转换为SQL,而是在内存中进行评估,并且由于Ignored includes和缺少延迟加载支持而在第二种情况下失败。

在可能的情况下使用Expression<Func<...>>总是更好,因为它们被转换为SQL并在数据库端进行评估,所以包括无所谓。

在你的情况下,很容易改变_exclude变量的类型(分配它的lambda语法保持不变),并在Where上使用链式&&

private Expression<Func<Employee, bool>> _exclude;

(基于过滤器语义,它实际上应该被称为_include_filter,但无论如何)

_exclude = (subject) =>
  !subject.IsDeleted && subject.Location.Department.Company.GroupId.Equals(_groupId);

现在可行:

Employee theEmployee = db.Employees
    .Include(e=>e.Location)
    .ThenInclude(e => e.Department)
    .ThenInclude(e => e.Company)
    .Where(e => e.EmployeeId == EmployeeId)
    .Where(_exclude)
    .FirstOrDefault();

以及:

string employeeId = db.Employees
    // not needed, but will not hurt if used, will be ignored anyway
    //.Include(e=> e.Location)
    //.ThenInclude(e => e.Department)
    //.ThenInclude(e => e.Company)
    .Where(e => e.EmployeeId == EmployeeId)
    .Where(_exclude)
    .Select(e => e.EmployeeId)
    .FirstOrDefault();