为此寻求帮助-我是Entity Framework / Linq查询方法的新手。下面的SQL语句从SQL Server数据库中获取我需要的数据。
任何人都可以帮忙解决一下Linq中的外观,以便我了解其工作原理吗?
SELECT st.departure_time, t.trip_headsign, r.route_short_name, r.route_long_name
FROM stop_times st
LEFT JOIN stops s ON s.stop_id = st.stop_id
LEFT JOIN trips t ON t.trip_id = st.trip_id
LEFT JOIN routes r ON r.route_id = t.route_id
LEFT JOIN calendar c ON c.service_id = t.service_id
WHERE st.stop_id = '2560378' AND c.start_date <= 20190122 AND c.end_date >= 20190122 AND c.tuesday = 1
ORDER BY st.departure_time ASC
使用如下所示的Entity等会选择所有停靠点
using (var db = new TestEntities())
{
var query = from b in db.Stops select b;
}
答案 0 :(得分:1)
我将从您的前几对联接开始,这样您就可以得到其余的联接。您还需要完成WHERE
子句。
var query = (from ST in db.stop_times
join S in db.stops on ST.stop_id equals S.stop_id into Ss
from S in Ss.DefaultIfEmpty()
join T in db.trips on ST.trip_id equals T.trip_id into Ts
from T in Ts.DefaultIfEmpty()
where ST.stop_id = '2560378'
select new YourCustomObject
{
DepartureTime = ST.departure_time,
TripHeadsign = T.trip_headsign
}).OrderBy(x => x.DepartureTime);
您会看到以下是LEFT JOIN
:
join T in db.trips on ST.trip_id equals T.trip_id into Ts
from T in Ts.DefaultIfEmpty()
答案 1 :(得分:0)
A,您忘记提供班级的相关部分。现在我们必须从您的SQL中提取它们,希望我们得出正确的结论。下次考虑添加您的类定义。
此外,了解基于SQL查询的需求可能会很方便,现在我们必须从SQL中提取需求。
要求:ID == 2560378的StopTime属于一次Trip。此行程有零个或更多路线。从此StopTime中,选择Trip及其所有具有StartDate <= ...和EndDate> = ...和TuesDay == 1的路线。从结果项中获取属性DepartureTime,StopTime,HeadSign,... >
在我看来,您的数据库具有StopTimes,Stops,Trips和Calendars表。
显然,它们之间存在关系。有些可能是一对多的,有些可能是多对多的,或者是零或一。从您的查询中很难确定这些关系。
在我看来,每个Trip
都有零个或多个StopTimes
,每个StopTime
恰好属于一个Trip
(一对多)。 StopTimes
和Stops
之间也存在一对多:每个StopTime
的零个或多个Stops
,每个Stop
恰好属于一个{ {1}}。此外:StopTime
有几个Trip
和几个Routes
。
这些关系中的某些关系可能不是一对多的,而是多对多的或一对一的。原理保持不变。
如果您遵循e ntity framework code first conventions,,则您的课程将类似于以下内容:
Calendars
等等: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
将会非常相似。
在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系。
因为我遵循了约定,所以实体框架能够检测主键和外键以及表之间的关系。不需要属性,也不需要流畅的API。如果要使用其他标识符,则可能需要属性或流畅的API。
一旦您正确地设计了类,尤其是表之间的关系(虚拟ICollection),查询就会很简单:
Calendars
因为实体框架知道我的关系,所以知道使用虚拟属性时要执行哪个(组)联接。
某些人确实更喜欢使用联接。好吧,如果您可以说服项目负责人,以下内容更易于阅读/测试/维护:
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);