我想通过Order.CustomerID对数据进行分组(使用Northwind作为示例)。
IN SQL看起来像这样:
Select
o.CustomerID,
SUM(od.Quantity * od.UnitPrice * (1-od.Discount))
FROM Orders o INNER JOIN [Order Details] od ON o.OrderID = od.OrderID
GROUP BY o.CustomerID
如何使用Linq加载该数据?
我试过
var order = context.Customers.Include("Orders.Order_Details")
.SelectMany(x => x.Orders)
.Select(x => new
{
Customer = x.Customer,
Sum = x.Order_Details.Sum(y => (float)(y.Quantity * y.UnitPrice) * (1 - y.Discount))
})
.GroupBy(x => x.Customer)
.Select(x => new
{
x.Key.CompanyName,
Sum = x.Sum(y => y.Sum)
});
但是,所产生的查询是丑陋而且太长。 任何帮助将不胜感激。
答案 0 :(得分:1)
显然,客户和订单之间存在一对多的关系:每个客户都有零个或多个订单,每个订单只属于一个客户。
Orders和OrderDetails之间也存在一对多的关系:每个Order都有零个或多个OrderDetails,每个OrderDetail只属于一个Order。
此外,OrderDetail有Quantity,UnitPrice和Discount。
现在,根据您的SQL语句,您希望将所有订单分组到同一客户的订单组中。从您想要CustomerId的每个Group,以及该组中所有Orders的所有OrderDetails的价格总和。
使用LINQ可以使用多种方法。您试图从所有客户开始:
var totalOfAllOrdersOfCustomers = dbContext.Customers
.Select(customer => new
{
CustomerId = customer.Id,
TotalAllOrders = customer.Orders
.SelectMany(order => orderDetails)
.Select(orderDetail => orderDetail.Quantity * orderDetail.UnitPrice
* (1-orderDetail.Discount))
.Sum();
}
用语言表达:从每个客户那里获取Id。同时获取此客户的所有订单的所有OrderDetails(= SelectMany
)。从每个OrderDetail使用公式计算价格,并将所有这些价格相加。
这将提供与您的SQL查询非常相似的内容。但是,存在差异:如果您的客户没有任何订单,您仍然可以获得CustomerId和Sum等于零的记录。
如果这是你想要的,你应该使用这种方法。
要获得没有任何订单的客户,SQL内部将使用Orders表从Customers表执行左外连接。通过查看订单表,您无法找到没有订单的客户。
您的SQL语句显示您不希望客户没有任何订单。如果是这种情况,您不必使用Customers表来获得结果:
var totalOfAllCustomersThatHaveOrders = dbContext.Orders
.GroupBy(order => order.CustomerId)
.Select(group => new
{
CustomerId = group.Key,
TotalAllOrders = group.SelectMany(group.OrderDetails)
.Select(orderDetail => orderDetail.Quantity * orderDetail.UnitPrice
* (1-orderDetail.Discount))
.Sum();
}
用语言表示:接受所有订单。将它们放入具有相同CustomerId(= GroupBy
)的订单组中。从每个组中取Key
(即组中所有订单的CustomerId)并将其分配给CustomerId。第二部分类似于第一个解决方案:从该组中的所有订单中获取所有OrderDetails(= SelectMany
),并根据公式计算OrderDetail的价格。最后总结所有这些价格并将此总和分配给TotalOrders
因此,第一个需要额外的左外连接,因为它为您提供没有订单的客户。第二个更简单,但如果没有给你那些尚未订购的客户。
请注意,在您的最终结果中,您对客户的所有了解都是ID。如果您在此声明之后立即获取一些客户数据("哦,现在我已经获得了CustomerId,我喜欢客户名称和地址"),我' d使用第一种方法,从Customer表开始,然后选择所需的所有客户属性。这将为您节省一次数据库往返。
答案 1 :(得分:0)
我认为您不需要分组,因为所有实体都已链接:
context.Customers.Include("Orders.Order_Details").
Select(c => new
{
Customer = c,
Total = c.Orders.SelectMany(o => o. Order_Details).
Sum(d => d.Quantity * d.UnitPrice * (1-d.Discount))
});