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

E-B*_*Bat 1 .net c# linq entity-framework entity-framework-core

我有以下委托声明:

private Func<Employee, bool> _exclude;
Run Code Online (Sandbox Code Playgroud)

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

_exclude = (subject) =>
  !subject.IsDeleted && subject.Location.Department.Company.GroupId.Equals(_groupId);
Run Code Online (Sandbox Code Playgroud)

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

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

但是当我只想检索单个值时它失败了,例如,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();
Run Code Online (Sandbox Code Playgroud)

由于subject.Location值为null,因此上述在Func 委托_exclude 中无法生成NullReferenceException ,这意味着传递给委托的员工未按照Includes 完全实现。

当需要一个成熟的员工但投影查询失败时,它成功实现员工图的原因是什么,或者在这种情况下应该如何组合查询?

我正在使用 EF Core

Iva*_*oev 5

当需要一个成熟的员工但投影查询失败时,它成功实现员工图的原因是什么

在这两种情况下,_exclude(e)都没有转换为 SQL,而是在内存中计算,并且在第二种情况下失败,因为忽略包含和缺乏延迟加载支持。

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

在您的情况下,很容易更改_exclude变量的类型(分配它的 lambda 语法保持不变)并使用 chainedWhere代替 on &&

private Expression<Func<Employee, bool>> _exclude;
Run Code Online (Sandbox Code Playgroud)

(基于过滤器语义,它应该真正被称为_includeor _filter,但无论如何)

_exclude = (subject) =>
  !subject.IsDeleted && subject.Location.Department.Company.GroupId.Equals(_groupId);
Run Code Online (Sandbox Code Playgroud)

现在这有效:

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

还有这个:

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();
Run Code Online (Sandbox Code Playgroud)