如何使用linq和EF在子导航属性上使用where子句

时间:2018-04-11 09:43:04

标签: c# linq

我的模型有一个导航属性,此导航属性具有另一个子导航属性。我需要在子导航属性上使用where clause来过滤结果。

我试图使用linq查询但无法获得结果

_context.Set<Job>().Include(x=>x.Premises).ThenInclude(y=>y.Station.Where(s=>s.)

以下sql join为我提供了理想的结果

select * 
  from [dbo].[JOB] J inner join 
       [dbo].[PREMISES] P on J.PremisesId = P.Id inner join 
       [dbo].[STATION] S on P.StationCode=S.StationCode
 where S.StationCode = '001'

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

请注意这些类似的LINQ语句:

var jobs = db.Jobs
                .Include(j => j.Premises)
                .Include(j => j.Premises.Select(p => p.Stations))
                .ToList();

var stations = db.Stations
                .Include(s => s.Premise)
                .Include(s => s.Premise.Job)
                .ToList();

虽然返回类型不同,但实质上是在内存中保存相同的数据。我也可以使用第二个来获得所有工作:

var jobs_from_stations = stations.Select(s => s.Premise.Job).Distinct();

jobs_from_stationsjobs都将包含完全相同的数据。

虽然过滤存在差异。

如果您要在此查询中添加Where()子句,它将以不同的方式工作。

第一个查询将在Job实体的范围内进行过滤,而第二个查询将在Station实体的范围内进行过滤。
由于您当前正在尝试根据工作站属性进行过滤,因此建议使用第二个查询:

var stations = db.Stations
                .Include(s => s.Premise)
                .Include(s => s.Premise.Job)
                .Where(s => s.StationCode == "001")
                .ToList();

如果您希望返回类型为作业列表:

var jobs = db.Stations
                .Include(s => s.Premise)
                .Include(s => s.Premise.Job)
                .Where(s => s.StationCode == "001")
                .Select(s => s.Premise.Job)
                .Distinct()
                .ToList();

请注意,仍然可以使用第一个查询,但它变得更加冗长和笨拙:

var jobs = db.Jobs
                .Include(j => j.Premises)
                .Include(j => j.Premises.Select(p => p.Stations))
                .Where(j => j.Premises.Any(p => p.Stations.Any(s => s.StationCode == "001")))
                .ToList();

根据经验,我总是试图从孩子开始并继续努力。正如您在上面的示例中所看到的,它使过滤更容易。但也许你也注意到它也使Include()语句变得简单:

.Include(s => s.Premise)
.Include(s => s.Premise.Job)

而不是

.Include(j => j.Premises)
.Include(j => j.Premises.Select(p => p.Stations))

虽然这两个示例在功能上是等效的,但是如果要包含从您开始的位置删除多个关系的实体,则必须为每个级别添加Select()变得非常麻烦。