我有以下委托声明:
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
答案 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();