将SQL语句转换为Linq语句(3表左连接+其中)

时间:2014-12-17 05:47:56

标签: sql linq entity-framework left-join where-clause

这是我需要转换为Linq的工作sql:

select * from dbo.Pod p
 left join dbo.PodEvent pe on p.PodId = pe.Pod_PodId
 left join dbo.Event e on pe.Event_EventId = e.EventId
where e.StartDateTime >= '2014-12-24 09:00:00.000' 
  and e.EndDateTime <= '2014-12-24 14:30:00.000'

我一直在尝试不同帖子的建议,这是我能做的最好的,问题在于它是一个内部联接,我需要它作为左联接,所以我可以在给定的时间内获得所有的pod间隔:

List<Pod> pods =
    (from p in db.Pods
     join pe in db.PodEvents on p.PodId equals pe.Pod.PodId
     join e in db.Events on pe.Event.EventId equals e.EventId
     where
     e.StartDateTime == userInfo.StartDateTime
      &&
     e.EndDateTime <= userInfo.EndDateTime
     select p).ToList();

由于

1 个答案:

答案 0 :(得分:3)

鉴于SQL中的WHERE过滤器将有效地使Left Outer Join成为冗余,因为任何失败的JOINS将为filtered out by the WHERE clause,您可以使用此事实通过结点手动投影INNER JOIN没有导航的表(性能可能很差):

var pods = db.Events.Where(e => e.StartDateTime >= userInfo.StartDateTime
                                 && e.EndDateTime < userInfo.EndDateTime)
                     .Join(db.PodEvents, 
                            e => e.EventID, 
                            pe => pe.EventId,
                            new (e, pe) => {
                               Event = e,
                               PodEvent = pe,
                               Pod = db.Pods.Single(p => p.PodId == pe.PodID)
                            })
                      .SelectMany(x => x.Pod);

但是,鉴于您已通过pe.Event.EventId导航,为什么不在所有三个表上修复导航,这样可以更简单:

var pods = db.Events.Where(e => e.StartDateTime >= userInfo.StartDateTime
                                && e.EndDateTime < userInfo.EndDateTime)
                    .SelectMany(e => e.PodEvents.Select(pe => pe.Pod));

此外,如果PodEvent只是一个连接表(EventId, PodId) - 通过将其建模为多个:EF中的许多,您可以完全避免PodEvent连接实体,{{{ 1}}和Event将直接导航。