简体   繁体   English

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

[英]Passing delegate to linq query in EF Core

I have the following delegate declaration: 我有以下委托声明:

private Func<Employee, bool> _exclude;

Then elsewhere in my code I set its value to this: 然后在代码的其他地方,将其值设置为:

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

The objective is to reuse the filter across all queries. 目的是在所有查询中重用过滤器。 This works fine if I'm going to materialize an employee instance like this: 如果我要像这样实现一个员工实例,这将很好地工作:

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

But it fails when I just wanted to retrieve a single value,like for instance, EmployeeId: 但是,当我只想检索一个值(例如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();

The above fails producing a NullReferenceException in the Func delegate _exclude because subject.Location value is null, that means the employee passed to the delegate is not full materialized as per Includes. 上面的方法无法在Func委托_exclude中产生NullReferenceException,因为subject.Location值为null,这意味着传递给委托的雇员没有按照Includes完全实现。

What can be the cause that it successfully materialize the Employee graph when a full fledged Employee is needed but fails for the projection query, or how should the query be composed in this cases? 当需要成熟的Employee但无法进行投影查询时,它可以成功地实现Employee图的原因是什么?或者在这种情况下应如何构成查询?

I am using EF Core 我正在使用EF Core

What can be the cause that it successfully materialize the Employee graph when a full fledged Employee is needed but fails for the projection query 是什么原因,当需要完整的Employee时却成功实现了Employee图,但无法进行投影查询

In both cases the _exclude(e) is not translated to SQL, but evaluated in memory, and it fails in the second scenario because of the Ignored includes and the lack of lazy loading support. 在这两种情况下, _exclude(e)都不会转换为SQL,而是在内存中进行评估,并且在第二种情况下会失败,因为忽略了包含 ,并且缺少惰性加载支持。

It's always better to use Expression<Func<...>> when possible because they are translated to SQL and evaluated at database side, so includes don't matter. 尽可能使用Expression<Func<...>>总是更好,因为它们会转换为SQL并在数据库端进行评估,因此包括无关紧要。

In your case it's quite easy to change the type of _exclude variable (the lambda syntax of assigning it remains the same) and use chained Where instead on && : 在您的情况下,更改_exclude变量的类型(分配它的lambda语法保持不变)并在&&上使用链接式Where是很容易的:

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

(based on the filter semantics, it should really be called _include or _filter , but anyway) (根据过滤器的语义,它实际上应该称为_include_filter ,但无论如何)

and

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

Now this works: 现在工作:

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

as well as this: 以及这个:

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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM