使用 Linq 为每个客户带回最后 3,4...n 个订单

发布于 2024-10-30 10:32:12 字数 1563 浏览 1 评论 0原文

我有一个包含客户订单的数据库。 我想使用 Linq(到 EF)查询数据库以返回每个客户的最后(最近)3,4...n 订单。

笔记: 客户 1 在过去一小时内可能刚刚下了 12 个订单;但客户 2 可能自上周以来就没有做过任何事情。

我一生都无法弄清楚如何在 linq (lambda 表达式)中编写查询来获取数据集。

有什么好主意吗?

编辑: 客户和订单是一种简化。我正在查询的表实际上是各种 Web 服务的出站消息的记录。描述为客户和订单似乎更容易。关系是一样的。 我正在构建一个任务来检查每个 Web 服务的最后 n 条消息,以查看是否存在任何故障。我们想要网络服务的半实时健康状态。

@CoreySunwold
我的桌子看起来有点像这样:
MessageID、WebserviceID、SentTime、状态、消息、错误

或者来自客户/订单上下文(如果这样更容易):
OrderID、CustomerID、StatusChangedDate、Status、WidgetName、Comments

编辑 2: 我最终解决了一些问题
(向@StephenChung致敬,他基本上想出了完全相同的方法,但是是在经典的linq中)

var q = myTable.Where(d => d.EndTime > DateTime.Now.AddDays(-1))< br> .GroupBy(g => g.ConfigID)
.Select(g =>新 { 配置ID = g.Key, 数据 = g.OrderByDescending(d => d.EndTime) .Take(3).Select(s => 新 { s.状态, 发送时间 }) }).ToList();

执行确实需要一段时间。所以我不确定这是否是最有效的表达方式。

I have a database with customers orders.
I want to use Linq (to EF) to query the db to bring back the last(most recent) 3,4...n orders for every customer.

Note:
Customer 1 may have just made 12 orders in the last hr; but customer 2 may not have made any since last week.

I cant for the life of me work out how to write query in linq (lambda expressions) to get the data set back.

Any good ideas?

Edit:
Customers and orders is a simplification. The table I am querying is actually a record of outbound messages to various web services. It just seemed easer to describe as customers and orders. The relationship is the same.
I am building a task that checks the last n messages for each web service to see if there were any failures. We are wanting a semi real time Health status of the webservices.

@CoreySunwold
My table Looks a bit like this:
MessageID, WebserviceID, SentTime, Status, Message, Error,

Or from a customer/order context if it makes it easer:
OrderID, CustomerID, StatusChangedDate, Status, WidgetName, Comments

Edit 2:
I eventually worked out something
(Hat tip to @StephenChung who basically came up with the exact same, but in classic 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();

It does take a while to execute. So I am not sure if this is the most efficient expression.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

岁吢 2024-11-06 10:32:12

这应该给出每个客户的最后 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 个,然后将其放入视图中。

This should give the last 3 orders of each customer (if having orders at all):

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()
}

However, I suspect this will force the database to return the entire Orders table before picking out the last 3 for each customer. Check the SQL generated.

If you need to optimize, you'll have to manually construct a SQL to only return up to the last 3, then make it into a view.

浊酒尽余欢 2024-11-06 10:32:12

您可以使用 SelectMany 来实现此目的:

customers.SelectMany(x=>x.orders.OrderByDescending(y=>y.Date).Take(n)).ToList();

You can use SelectMany for this purpose:

customers.SelectMany(x=>x.orders.OrderByDescending(y=>y.Date).Take(n)).ToList();
不可一世的女人 2024-11-06 10:32:12

这个怎么样?我知道它可以与常规集合一起使用,但不知道 EF。

yourCollection.OrderByDescending(item=>item.Date).Take(n);

How about this? I know it'll work with regular collections but don't know about EF.

yourCollection.OrderByDescending(item=>item.Date).Take(n);
ゃ人海孤独症 2024-11-06 10:32:12
var ordersByCustomer = 
db.Customers.Select(c=>c.Orders.OrderByDescending(o=>o.OrderID).Take(n));

这将返回按客户分组的订单。

var ordersByCustomer = 
db.Customers.Select(c=>c.Orders.OrderByDescending(o=>o.OrderID).Take(n));

This will return the orders grouped by customer.

偷得浮生 2024-11-06 10:32:12
var orders = orders.Where(x => x.CustomerID == 1).OrderByDescending(x=>x.Date).Take(4);

这将需要最后 4 个订单。具体查询取决于你的表/实体结构。

顺便说一句:您可以将 x 作为订单。因此,您可以这样阅读:获取 order.CustomerID 等于 1 的订单,按 order.Date 获取 OrderThem 并获取前 4 行。

var orders = orders.Where(x => x.CustomerID == 1).OrderByDescending(x=>x.Date).Take(4);

This will take last 4 orders. Specific query depends on your table / entity structure.

Btw: You can take x as a order. So you can read it like: Get orders where order.CustomerID is equal to 1, OrderThem by order.Date and take first 4 'rows'.

年少掌心 2024-11-06 10:32:12

有人可能会在这里纠正我,但我认为使用单个查询执行此操作即使不是不可能,也可能非常困难。我会使用存储过程和类似的东西,

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"

我已经有一段时间没有使用这种语法了,所以它可能不太正确,但如果我理解这个问题,那么我认为这是最好的方法。

Somebody might correct me here, but i think doing this is linq with a single query is probably very difficult if not impossible. I would use a store procedure and something like this

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"

I've not used this syntax for a while so it might not be quite right, but if i understand the question then i think this is the best approach.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文