Увы, вы забыли предоставить соответствующие части ваших классов. Теперь мы должны извлечь их из вашего SQL, надеясь сделать правильные выводы. В следующий раз подумайте о добавлении определений классов.
Кроме того, может быть полезно узнать требование, на котором вы основали свой запрос SQL, теперь нам нужно извлечь это требование из вашего SQL.
Требование: StopTime с Id == 2560378 относится к одной Поездке. Эта поездка имеет ноль или более маршрутов. Из этого StopTime возьмите Trip и все ее маршруты, имеющие StartDate <= ... и EndDate> = ... и ВтDay == 1. Из полученных элементов возьмите свойства DepartureTime, StopTime, HeadSign, ...
Классы
Мне кажется, что в вашей базе данных есть таблицы StopTimes, Stops, Trips и Calendars.
Очевидно, между ними есть связь. Некоторые могут быть один ко многим, некоторые могут быть многими ко многим или один к нулю или одному. По вашему запросу сложно определить эти отношения.
Мне кажется, что каждый Trip
имеет ноль или более StopTimes
, и каждый StopTime
принадлежит ровно одному Trip
(один ко многим). Между StopTimes
и Stops
также существует отношение один ко многим: каждый StopTime
имеет ноль или более Stops
, и каждый Stop
принадлежит ровно одному StopTime
. Кроме того: Trip
имеет несколько Routes
, а также несколько Calendars
.
Может быть, некоторые из этих отношений не один-ко-многим, но многие-ко-многим или один-к-одному. Принцип остается прежним.
Если вы следовали первым соглашениям кода платформы e ntity, ваши классы будут похожи на следующие:
class Trip
{
public int Id {get; set;}
...
// Every Trip has zero or more StopTimes (one-to-many):
public virtual ICollection<StopTime> StopTimes {get; set;}
// Every Trip has zero or more Routes (one-to-many):
public virtual ICollection<Route> Routes {get; set;}
// Every Trip has zero or more Calendars (one-to-many):
public virtual ICollection<Calendar> Calendars {get; set;}
}
class StopTime
{
public int Id {get; set;}
...
// Every StopTime belongs to exactly one Trip using foreign key:
public int TripId {get; set;}
public virtual Trip Trip {get; set;}
// Every StopTime has zero or more Stops (one-to-many):
public virtual ICollection<Stop> Stops {get; set;}
}
class Route
{
public int Id {get; set;}
...
// every Route belongs to exactly one Trip (using foreign key)
public int TripId {get; set;}
public virtual Trip Trip {get; set;}
}
И т.д .: Stops
и Calendars
будут очень похожи.
В каркасе сущностей столбцы ваших таблиц представлены не виртуальными свойствами. Виртуальные свойства представляют отношения между таблицами.
Поскольку я следовал соглашениям, структура сущностей способна обнаруживать первичные и внешние ключи и отношения между таблицами. Нет необходимости ни в атрибутах, ни в беглости API. Если вы хотите использовать разные идентификаторы, могут потребоваться атрибуты или свободный API.
Запрос с использованием виртуальных свойств
Как только вы правильно спроектировали свои классы, особенно отношения между таблицами (виртуальная ICollection), ваш запрос будет простым:
var result = dbContext.StopTimes
.Where(stopTime => stopTime.Id == 2560378)
.SelectMany(stopTime => stopTime.Trip.Routes
.Where(route => route.StartDate <= 20190122 && route.EndDate >= 20190122)
(stopTime, route) => new
{
DepartureTime = stopTime.DepartureTime,
TripHeadSign = stopTime.Trip.HeadSign,
Route = new
{
ShortName = route.ShortName,
LongName = route.LongName,
},
// or, if you don't want a separate Route Property:
RouteShortName = route.ShortName,
RouteLongName = route.LongName,
})
.OrderBy(item => item.DepartureTime);
Поскольку структура сущностей знает мои отношения, она знает, какую (группу) объединяет для выполнения при использовании виртуальных свойств.
Запрос на фактическое соединение
Некоторые люди действительно предпочитают использовать соединения. Хорошо, если вы можете убедить своего руководителя проекта, что следующее лучше читаемо / тестируемо / поддерживаемо:
var result = dbContext.StopTimes
.Where(stopTime => stopTime.Id == 2560378) // keep only StopTimes with Id == ...
.Join(dbContext.Trips, // Join with Trips
stopTime => stopTime.TripId, // from every StopTime take the TripId
trip => trip.Id // from every Trip take the Id,
(stopTime, trip) => new // keep only the properties I need
{
DepartureTime = stopTime.DepartureTime,
TripHeadSign = trip.HeadSign
TripId = trip.Id, // Id is used in the next join
}
// join this joinResult with the eligible routes:
.Join(dbContext.Routes
.Where(route => route.StartDate <= ... && route.EndDate >= ...)
firstJoinResult => firstJoinResult.TripId,
route => route.TripId,
(firstJoinResult, route) => new
{
DepartureTime = firstJoinResult.DepartureTime,
TripHeadSign = firstJoinResult.TripHeadSign,
Route = new
{
ShortName = route.ShortName,
LongName = route.LongName,
},
})
.OrderBy(item => item.DepartureTime);
}