【问题标题】:Linq Query Join to Subquery with In clauseLinq Query 使用 In 子句加入子查询
【发布时间】:2019-07-15 14:17:43
【问题描述】:

我有一个来自旧应用程序的查询,我正在尝试将其转换为 Entity Framework Core 应用程序。我正在处理的关系是简单的一对多关系,其中一个订单可以有多个订单事件。旧查询如下所示:

select Order.Id, mostRecent.*
from Order
left join OrderEvent mostRecent 
on mostRecent.Id in (select top(1) Id 
                     from OrderEvent
                     where OrderEvent.OrdId = Order.Id 
                           and OrderEvent.PostDateTime is not null
                     order by OrderEvent.PostDateTime desc)
where Order.SomeColumn = 'some value'

我正在努力弄清楚如何在 LINQ 中编写此查询。在使用join 时,似乎除了equals 之外什么都不能使用,所以我首先尝试了类似的东西:

var test = (from order in _context.Ord.AsNoTracking()
            join mostRecentQuery in _context.OrdEvt.AsNoTracking()
            on (from orderEvent in _context.OrdEvt.AsNoTracking()
                where orderEvent.PostDateTime != null && orderEvent.OrdId == order.Id
                orderby orderEvent.PostDateTime descending
                select orderEvent.Id).FirstOrDefault()
            equals mostRecentQuery.Id
            into mostRecentResults
            from mostRecent in mostRecentResults.DefaultIfEmpty()
            select new
            {
               OrderId = order.Id,
               OrderEvent = mostRecent
            }).ToList();    

无论吐出什么 sql,它似乎都太慢了,我什至无法将它连接到 Sql Server 运行。但是,我可以在使用 Sqlite 时运行此查询,它会生成以下 sql:

SELECT 'big list of fields....'
  FROM "Ord" AS "order"
  LEFT JOIN "OrdEvt" AS "mostRecentQuery" ON COALESCE((
      SELECT "orderEvent0"."Id"
      FROM "OrdEvt" AS "orderEvent0"
      WHERE "orderEvent0"."PostDateTime" IS NOT NULL AND ("orderEvent0"."OrdId" = "order"."Id")
      ORDER BY "orderEvent0"."PostDateTime" DESC
      LIMIT 1
  ), X'00000000000000000000000000000000') = "mostRecentQuery"."Id"

这很接近我的目标,但我不确定为什么要使用 COALESCE 函数。

是否可以用 Linq 查询语法表示我要转换的查询?

【问题讨论】:

标签: c# sql linq entity-framework-core


【解决方案1】:

我不确定您的问题是什么,因为您忽略了它无法编译的原因。

这里是一个简单的例子,加入并为订单选择一个事件:

public class Order
{
    public int OrderId { get; set; }
    public string OrderName { get; set; }
}

public class OrderEvent
{
    public int OrderId { get; set; }
    public string EventName { get; set; }
    public DateTime Date { get; set; }
}

public static void Main(string[] args) // Here our Exe-Args are delivered to our program..
{

    List<Order> orders = new List<Order>()
    {
        new Order() { OrderId = 1, OrderName = "One" }
    };
    List<OrderEvent> orderEvents = new List<OrderEvent>()
    {
        new OrderEvent() { OrderId = 1, EventName = "EventTwo", Date = DateTime.Now.AddHours(-1) },
        new OrderEvent() { OrderId = 1, EventName = "EventOne", Date = DateTime.Now },
        new OrderEvent() { OrderId = 1, EventName = "EventThree", Date = DateTime.Now.AddHours(-2) },
        new OrderEvent() { OrderId = 2, EventName = "EventX", Date = DateTime.Now },
    };

    var tmp = orders.GroupJoin( // Join something to our orders
            orderEvents, // join all events
            o => o.OrderId, // key of our order
            e => e.OrderId, // foreign-key to order in our event
            (o, es) => // lambda-expression "selector". One order "o" and multiple events "es"
            es.OrderByDescending(e => e.Date) // We order our events
            .Select(s => new // we build a new object
            {
                OrderId = o.OrderId,
                OrderName = o.OrderName,
                RecentEvent = s.EventName
            }).First()); // we choose the object with biggest date (first after orderDesc)

    foreach (var item in tmp)
    {
        Console.WriteLine(item.OrderId + ", " + item.OrderName + ", " + item.RecentEvent);
    }

    tmp = from o in orders
               join e in orderEvents on o.OrderId equals e.OrderId into es
               select new
               {
                   OrderId = o.OrderId,
                   OrderName = o.OrderName,
                   RecentEvent = (from x in es orderby x.Date descending select x.EventName).First()
               };

    foreach (var item in tmp)
    {
        Console.WriteLine(item.OrderId + ", " + item.OrderName + ", " + item.RecentEvent);
    }
}

【讨论】:

  • 看起来编译错误只是一个错字或我忽略的东西。事实上,我能够在这个查询中进行最初的编译尝试。它似乎没有吐出我期待的sql。你的答案可以用查询语法格式化,还是只能用 lambda 语法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多