Entity Framework Core:使用导航属性而不是连接
Posted
技术标签:
【中文标题】Entity Framework Core:使用导航属性而不是连接【英文标题】:Entity Framework Core: using navigation properties instead of joins 【发布时间】:2021-09-15 16:19:12 【问题描述】:最近我将Navigation Properties
添加到没有任何FK 的EF Core
项目中,以便在尽可能多的查询中使用Include
而不是Join
,但我发现无论是sintax几乎所有查询都不适合我的需求(需要拆分为多个查询),或者我遗漏了一些东西,所以我举个例子,我想知道,使用Navigation Properties
你会如何获取特定 dayType 的所有 Stops 及其 Line 列表?:
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 => ?)
【问题讨论】:
【参考方案1】:如果我正确理解您的问题,您的查询可以大大简化。 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()
);
【讨论】:
以上是关于Entity Framework Core:使用导航属性而不是连接的主要内容,如果未能解决你的问题,请参考以下文章
在 Entity Framework Core 中使用 [ComplexType]
在 Entity Framework Core 中使用 SQL 视图
使用 Entity Framework Core 更新相关数据