将SQL查询转换为Linq以与实体框架一起使用

时间:2019-01-22 10:56:15

标签: c# entity-framework linq

为此寻求帮助-我是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;
}

2 个答案:

答案 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(一对多)。 StopTimesStops之间也存在一对多:每个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);