【问题标题】:Passing delegate to linq query in EF Core将委托传递给 EF Core 中的 linq 查询
【发布时间】:2017-01-23 20:05:53
【问题描述】:

我有以下委托声明:

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

【问题讨论】:

  • 检查数据,查看您经过的该员工的位置,我认为发生的情况是您的一名员工没有附加位置
  • @Zinov,每个员工都有一个位置,这是后端的必填字段。请记住,对于全体员工来说,它工作得很好,如果不是,它也应该失败。
  • 有什么理由使用Func&lt;...&gt;而不是Expression&lt;Func&lt;...&gt;&gt;
  • @IvanStoev,实际上没有。

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


【解决方案1】:

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

在这两种情况下,_exclude(e) 都不会转换为 SQL,而是在内存中进行评估,而在第二种情况下它会因为 Ignored includes 和缺乏延迟加载支持而失败。

尽可能使用Expression&lt;Func&lt;...&gt;&gt; 总是更好,因为它们被转换为 SQL 并在数据库端进行评估,因此包含无关紧要。

在您的情况下,很容易更改 _exclude 变量的类型(分配它的 lambda 语法保持不变)并在 &amp;&amp; 上使用链式 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();

【讨论】:

    猜你喜欢
    • 2018-05-07
    • 2020-03-29
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    相关资源
    最近更新 更多