Entity Framework 核心:使用导航属性而不是连接

Entity Framework Core: using navigation properties instead of joins

最近我将 Navigation Properties 添加到一个没有任何 FK 的 EF Core 项目中,以便在尽可能多的查询中使用 Include 而不是 Join ,但我发现要么 sintax 在几乎所有查询中都不适合我的需求(需要拆分成多个查询),要么我遗漏了一些东西所以我会举一个例子,我想知道,使用 Navigation Properties 如何获得特定 dayType 的所有站点及其线路列表?:

Stop
stopId
Point
pointId
stopId?
routeId
Route
routeId
serviceDetailId
ServiceDetail
serviceDetailId
serviceHeaderId
ServiceHeaderDay
serviceHeaderDayId
serviceHeaderId
dayType
ServiceHeader
serviceHeaderId
lineId
Line
lineId

当前使用 Join 的工作查询,我想使用 Include:

翻译
var query = (await context.Stop
    .Join(
        context.Point,
        (stop) => stop.stopId,
        (point) => point.stopId,
        (stop, point) => new { Stop = stop, Point = point })
    .Join(
        context.Route,
        (join) => join.Point.routeId,
        (route) => route.routeId,
        (join, route) => new { Stop = join.Stop, Route = route })
    .Join(
        context.ServiceDetail,
        (join) => join.Route.routeId,
        (serviceDetail) => serviceDetail.routeId,
        (join, serviceDetail) => new { Stop = join.Stop, ServiceDetail = serviceDetail })
    .Join(
        context.ServiceHeader,
        (join) => join.ServiceDetail.serviceHeaderId,
        (serviceHeader) => serviceHeader.serviceHeaderId,
        (join, serviceHeader) => new { Stop = join.Stop, ServiceHeader = serviceHeader })
    .Join(
        context.ServiceHeaderDay,
        (join) => join.ServiceHeader.serviceHeaderId,
        (serviceHeaderDay) => serviceHeaderDay.serviceHeaderId,
        (join, serviceHeaderDay) => new { Stop = join.Stop, ServiceHeader = join.ServiceHeader, ServiceHeaderDay = serviceHeaderDay })
    .Join(
        context.Line,
        (join) => join.ServiceHeader.lineId,
        (line) => line.lineId,
        (join, line) => new { Stop = join.Stop, ServiceHeaderDay = join.ServiceHeaderDay, Line = line })
    .Where(e => e.ServiceHeaderDay.DayType == "L")
    .Select(e => new { Stop = e.Stop, Line = e.Line })
    .Distinct();
    .ToListAsync())
    // The query ends here, this next step is just grouping by Stops and inserting each Line list into them.
    .GroupBy(e => e.Stop.stopId)
    .Select(e =>
    {        
        var stop = e.First().Stop;
        stop.Lines = e.Select(e => e.Line).ToList();
        return stop;
    })

使用Include失败的尝试之一:

context.Stop
    .Include(e => e.Points)
    .ThenInclude(e => e.Route)
    .ThenInclude(e => e.ServiceDetail)
    .ThenInclude(e => e.ServiceHeader)
    .ThenInclude(e => e.ServiceHeaderDay
        Where(e => e.DayType = "L")
    // Now I need to Include Line from ServiceHeader, but this is a of type ServiceHeaderDay 
    // and I think you can't use anonymous objects to carry all the tables you just include 
    // so I found people repeating the includes like this:
    .Include(e => e.Point)
    .ThenInclude(e => e.Route)
    .ThenInclude(e => e.ServiceDetail)
    .ThenInclude(e => e.ServiceHeader)
    .ThenInclude(e => e.Line)
    // This doesn't seem to work, but also how would be the select to get the Stops with all 
    // the lines for each Stop here?
    .Select(e => ?)

如果我正确理解你的问题,你的查询可以简化很多。 Include一般不是用来查询的,而是用来加载相关数据进行修改的。

var query = context.Stop
    .Where(s => s.Points.Any(p => p.Route.ServiceDetail.ServiceHeader.ServiceHeaderDay.DayType = 'L'))
    .Select(s => new 
    {
        Stop = s,
        Lines = s.Points.Where(p => p.Route.ServiceDetail.ServiceHeader.ServiceHeaderDay.DayType = 'L')
            .Select(p => p.Route.ServiceDetail.ServiceHeader.Line)
            .ToList()
    });