如何在LINQ的ThenInclude中访问父级Include属性进行筛选?
如何在LINQ ThenInclude的Where条件中访问父级实体属性?
实体关系与定义
Customer实体隶属于Organisation,同时被分配给特定的Staff;Staff可通过中间表OrganisationStaff隶属于多个Organisation。实体代码定义如下:
public class Customer { public string Name { get; set; } public int AssignedOrganisationId { get; set; } public Organisation AssignedOrganisation { get; set; } public int AssignedStaffId { get; set; } public Staff AssignedStaff { get; set; } } public class Organisation { public List<Staff> Staff { get; set; } } public class OrganisationStaff { public int OrganisationId { get; set; } public Organisation Organisation { get; set; } public int StaffId { get; set; } public Staff Staff { get; set; } public int ExtraInformationId { get; set; } // 该Staff在对应Organisation中的专属信息 } public class Staff { public List<OrganisationStaff> OrganisationStaff { get; set; } public List<Customer> Customers { get; set; } }
问题场景
查询Appointment实体时,尝试通过Include链加载关联数据,但在ThenInclude的Where条件中,无法访问上层Customer的AssignedOrganisationId,只能访问当前层级的Staff相关属性。目标SQL可以实现该关联过滤:
SELECT * FROM public."Customer" C INNER JOIN Staff S ON S.Id = C.AssignedStaffId INNER JOIN OrganisationStaff OS ON OS.StaffId = S.Id INNER JOIN Organisation O ON O.Id = OS.OrganisationId WHERE C.Id = 10 and OS.OrganisationId = C.AssignedOrganisationId;
需要将这个SQL逻辑转换成LINQ Lambda表达式,且不能使用常量值,要动态关联Customer的AssignedOrganisationId。
解决方案
EF Core的过滤Include(即ThenInclude中嵌套的Where)只能访问当前导航层级的属性,无法直接引用上层父实体的属性。以下是两种可行的实现方式:
方案一:投影查询(推荐)
直接通过投影构建需要的对象结构,在投影逻辑中明确关联过滤条件,完美匹配目标SQL的逻辑:
await DbSet .Where(a => a.Id == customerId) .Select(a => new { Appointment = a, Customer = a.Customer, AssignedStaff = a.Customer.AssignedStaff, // 过滤出Staff在当前Customer所属Organisation下的关联数据 StaffOrganisation = a.Customer.AssignedStaff.OrganisationStaff .Where(os => os.OrganisationId == a.Customer.AssignedOrganisationId) .Select(os => os.Organisation) .FirstOrDefault() }) .SingleOrDefaultAsync();
这种方式不需要依赖Include链的限制,直接在投影中完成层级关联与过滤,性能更优。
方案二:分两次查询(适合特定场景)
如果业务场景允许,可以先查询目标Customer的AssignedOrganisationId,再将其作为参数带入Include的过滤条件:
var targetOrgId = await DbContext.Customers .Where(c => c.Id == customerId) .Select(c => c.AssignedOrganisationId) .SingleOrDefaultAsync(); if (targetOrgId != 0) // 假设Id不为0表示有效 { var result = await DbSet .Include(a => a.Customer) .ThenInclude(c => c.AssignedStaff) .ThenInclude(s => s.OrganisationStaff.Where(os => os.OrganisationId == targetOrgId)) .ThenInclude(os => os.Organisation) .Where(a => a.Id == customerId) .SingleOrDefaultAsync(); }
该方案需要两次数据库查询,仅适合不需要实时关联单个上下文的场景。
内容的提问来源于stack exchange,提问作者Alison PK
相关产品推荐
相关产品推荐

