我有一个包含客户订单的数据库。我想使用 Linq(到 EF)查询数据库,为每个客户带回最后(最新的)3,4...n 个订单。
注意:客户 1 可能在过去一小时内刚刚下了 12 个订单;但客户 2 可能自上周以来就没有做过任何工作。
我一生都无法弄清楚如何在 linq(lambda 表达式)中编写查询以取回数据集。
有什么好主意吗?
编辑:客户和订单是一种简化。我正在查询的表实际上是发送到各种 Web 服务的出站消息的记录。描述为客户和订单似乎更容易。关系是一样的。我正在构建一个任务,用于检查每个 Web 服务的最后 n 条消息,以查看是否有任何失败。我们想要网络服务的半实时运行状况。
@CoreySunwold我的表格看起来有点像这样:
消息 ID, 网络服务ID, 发送时间, 状态, 消息, 错误,
或者从客户/订单上下文中,如果它使它更容易:
订单 ID、客户 ID、状态更改日期、状态、小部件名称、注释
编辑 2:我最终想出了一些办法
(帽子提示给@StephenChung谁基本上想出了完全相同的,但在经典的linq中)
var q = myTable.Where(d => d.EndTime > DateTime.Now.AddDays(-1))
.GroupBy(g => g.ConfigID)
.Select(g =>new
{
ConfigID = g.Key,
Data = g.OrderByDescending(d => d.EndTime)
.Take(3).Select(s => new
{
s.Status,
s.SentTime
})
}).ToList();
执行确实需要一段时间。所以我不确定这是否是最有效的表达方式。
这应该给出每个客户的最后 3 个订单(如果有订单):
from o in db.Orders
group o by o.CustomerID into g
select new {
CustomerID=g.Key,
LastOrders=g.OrderByDescending(o => o.TimeEntered).Take(3).ToList()
}
但是,我怀疑这会强制数据库在为每个客户挑选最后 3 个之前返回整个 Orders 表。 检查生成的 SQL。
如果需要优化,则必须手动构造一个 SQL,使其最多只返回最后 3 个,然后将其放入视图中。
您可以使用 SelectMany 来实现此目的:
customers.SelectMany(x=>x.orders.OrderByDescending(y=>y.Date).Take(n)).ToList();
这个怎么样?我知道它可以与常规集合一起使用,但不了解 EF。
yourCollection.OrderByDescending(item=>item.Date).Take(n);
var ordersByCustomer =
db.Customers.Select(c=>c.Orders.OrderByDescending(o=>o.OrderID).Take(n));
这将返回按客户分组的订单。
var orders = orders.Where(x => x.CustomerID == 1).OrderByDescending(x=>x.Date).Take(4);
这将需要最后 4 个订单。具体查询取决于您的表/实体结构。
顺便说一句:你可以把x作为订单。所以你可以这样读:在订单的地方获取订单。客户 ID 等于 1,按订单订购。日期并取前 4 行。
有人可能会在这里纠正我,但我认为使用单个查询来做到这一点可能是非常困难的,如果不是不可能的话。我会使用商店程序和类似的东西
select
*
,RANK() OVER (PARTITION BY c.id ORDER BY o.order_time DESC) AS 'RANK'
from
customers c
inner join
order o
on
o.cust_id = c.id
where
RANK < 10 -- this is "n"
我已经有一段时间没有使用这种语法了,所以它可能不太正确,但如果我理解这个问题,那么我认为这是最好的方法。