【问题标题】:Convert this SQL Query to a Linq Lambda Expression将此 SQL 查询转换为 Linq Lambda 表达式
【发布时间】:2015-10-01 16:01:36
【问题描述】:

我有以下 SQL:

select Monitor.* from Monitor 
left join Queue on Queue.MonitorID = Monitor.MonitorID
and Queue.QueueID = (select top 1 Queue.QueueID from Queue where Queue.MonitorID = Monitor.MonitorID order by Queue.Created)
where Queue.Created is null or Queue.Created < 'DateTimeValue'

如果您能想出更好的方法来获取该信息,该查询将选择队列已过期或丢失的所有“监视器”。

此查询的结果是需要运行的过期项目。我正在使用 EF6。

我正在尝试将其从 SQL 转换为 Linq Lambda,我尝试了 Linqer,但它似乎没有输出 Lambda 示例,或者我找不到实现它的设置。

那么,有人可以帮助指导我转换此查询并提供改进(如果有的话)吗?我知道子查询是性能杀手...

一旦我看到它完成了,一旦我觉得我将能够学习语法。

我专门在 linq/lambdas 中寻找这种连接语法的示例

【问题讨论】:

  • 我很好奇,看到您有一个有效的查询,为什么不直接查询数据库,而不是使用 LINQ?
  • 我很困惑,因为您的原始查询看起来错误。 JOIN 不应该在Queue.MonitorID=Monitor.MonitorID 上吗?
  • 修复原始查询拼写错误,谢谢!
  • @user2366842 只是想学习其他方法

标签: c# sql-server linq lambda


【解决方案1】:

如果您使用带有导航属性的实体框架,则为:

var result=db.Monitors
  .Select(m=> new {
    monitor=m,
    queue=m.Queues.OrderByDescending(q=>q.Created).FirstOrDefault()
  })
  .Where(m=>m.queue.Created==null || m.queue.Created < DateTimeValue);

【讨论】:

  • 忘记新建匿名类new { monitor=m, queue=...}
  • @RobertMcKee 有趣,这看起来很有希望,但我当然有一些问题......这会返回一个带有监视器和队列的匿名对象,在我的情况下,我真的只需要监视器,所以会您在返回显示器的位置之后再选择一次?我假设您是这样写的,因为我在示例中选择了 *。谢谢你,这很有帮助。
  • 是的,只需在末尾添加另一个选择,如 .Select(m=&gt;m.monitor);,或者您可以重写 Where 子句,如:.Where(m=&gt;m.Queues.OrderByDescending(q=&gt;q.Created).FirstOrDefault()==null || m.Queues.OrderByDescending(q=&gt;q.Created).FirstOrDefault().Created&lt;DateTimeValue); 并完全删除选择。
【解决方案2】:

您可以只查询所有没有在阈值之后创建任何队列的监视器。

var result = db.Monitors
  .Where(m => !m.Queues.Any(q => q.Created >= DateTimeValue));

我认为在这里使用显式连接没有令人信服的理由。事实上,很少有惯用的 EF 查询。

【讨论】:

    【解决方案3】:

    我认为您的加入不太正确,因为您将队列留在了监视器上,队列必须存在,但监视器可能不存在。它也只会返回一个队列,因为您只使用子查询中的第一个队列。我想你想把 SQL 语句调整为

     select * from Monitor 
     left join Queue on Monitor.MonitorID = Queue.QueueID
     and Queue.QueueID in (select max(Queue.QueueID) from Queue group by Queue.MonitorID)
     /*this assumes queues are stored in sequential order*/
     where Queue.Created is null or Queue.Created < 'DateTimeValue'
    

    那么你可以编写如下的linq语句

     var monitors = _context.Set<Monitor>();
     var queues = _context.Set<Queue>();
    
     var queueIds = queues
          .GroupBy(q => q.MonitorID)
          .Select(q => q.Max(x => x.QueueID));
    
     return monitors
          .GroupJoin(queues.Where(q => queueIds.Contains(q.QueueID)), 
                     m => m.MonitorID, 
                     q => q.QueueID, 
                     (m, q) => new { monitor = m, queue = q.FirstOrDefault() })
          .Where(x => x.queue == null || x.queue.Created < date);
    

    【讨论】:

    • 您的子查询返回每个监视器 ID 的最大队列 ID。这不是一个标量值,因此您无法将其与等于进行比较。
    • 你说的很对,对不起,你能再帮我复习一遍吗?
    • @juharr 感谢您了解这一点。我更正了 SQL
    猜你喜欢
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    相关资源
    最近更新 更多