我如何改进这个Linq查询(一种旋转)
本文关键字:一种 旋转 查询 何改进 Linq | 更新日期: 2023-09-27 18:17:36
我有这个实体:
public class Delivery
{
public int Id { get; set; }
public int ProductId { get; set; }
public int CustomerId { get; set; }
public int Quantity { get; set; }
public DateTime DeliveryDate { get; set; }
public virtual Product Product { get; set; }
public virtual Customer Customer { get; set; }
}
我想按周显示交货,所以我写这个查询:
public override IEnumerable GetModelData(ApplicationDbContext context)
{
return context.Deliveries.GroupBy(x => x.Product).Select(x => new
{
Id=x.Key.Id,
Product = x.Key.Name,
Wk1 =(int?) x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 1).Sum(a => a.Quantity),
...
...
...
Wk46 = (int?)x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 46).Sum(a => a.Quantity),
Wk47 = (int?)x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 47).Sum(a => a.Quantity),
Wk48 = (int?)x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 48).Sum(a => a.Quantity),
Wk49 = (int?)x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 49).Sum(a => a.Quantity),
Wk50 = (int?)x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 50).Sum(a => a.Quantity),
Wk51 = (int?)x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 51).Sum(a => a.Quantity),
Wk52 = (int?)x.Where(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 52).Sum(a => a.Quantity),
}).ToList();
}
是否有可能用更小的查询获得预期的对象?
我在这个时刻大约有100个样本行在交付数据库表,我有填充,这种方式来获得数据不是最好的一个。
查询正在工作,我只想知道你是否有一个更好的方法来编写这种查询。
我认为使LINQ查询更短的唯一方法是以编程方式生成选择器。
但是,肯定有一种方法可以使生成的SQL查询更短(并且更高效)。代替不能很好地转换的Where(condition).Sum(expr)
结构,使用条件和,即Sum(condition ? expr : null)
,它产生更好的SQL:
Wk1 = x.Sum(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 1 ? a.Quantity : (int?)null),
Wk2 = x.Sum(a => SqlFunctions.DatePart("wk", a.DeliveryDate) == 2 ? a.Quantity : (int?)null),
...
我将在SQL查询中进行分组,但随后在内存中进行旋转。
public static IEnumerable GetModelData(ApplicationDbContext context)
{
return context.Deliveries
.GroupBy(x => new { x.Product.Id, x.Product.Name, Week = SqlFunctions.DatePart("wk", x.DeliveryDate) } )
.Select(x => new
{
Id = x.Key.Id,
Product = x.Key.Name,
Week = x.Key.Week,
Quantity = x.Sum(a => a.Quantity),
})
.AsEnumerable()
.GroupBy(x => new { x.Id, x.Product })
.Select(x => new
{
Id = x.Key.Id,
Product = x.Key.Product,
Wk1 = x.Sum(a => a.Week == 1 ? a.Quantity : 0),
Wk2 = x.Sum(a => a.Week == 2 ? a.Quantity : 0),
Wk51 = x.Sum(a => a.Week == 52 ? a.Quantity : 0),
Wk52 = x.Sum(a => a.Week == 53 ? a.Quantity : 0),
})
.ToList();
}
. asenumerable()上面的所有内容都作为一条SQL语句对数据库执行,下面的所有内容都在内存中执行。
下面是执行的SQL的跟踪。
SELECT
[GroupBy1].[K1] AS [ProductId],
[GroupBy1].[K2] AS [Name],
[GroupBy1].[K3] AS [C1],
[GroupBy1].[A1] AS [C2]
FROM ( SELECT
[Join1].[K1] AS [K1],
[Join1].[K2] AS [K2],
[Join1].[K3] AS [K3],
SUM([Join1].[A1]) AS [A1]
FROM ( SELECT
[Extent1].[ProductId] AS [K1],
[Extent2].[Name] AS [K2],
DATEPART(wk, [Extent1].[DeliveryDate]) AS [K3],
[Extent1].[Quantity] AS [A1]
FROM [dbo].[Deliveries] AS [Extent1]
INNER JOIN [dbo].[Products] AS [Extent2] ON [Extent1].[ProductId] = [Extent2].[Id]
) AS [Join1]
GROUP BY [K1], [K2], [K3]
) AS [GroupBy1]
如果你删除。asenumerable(),它将在服务器上全部运行。下面是SQL跟踪。
SELECT
[GroupBy2].[K1] AS [ProductId],
[GroupBy2].[K2] AS [Name],
[GroupBy2].[A1] AS [C1],
[GroupBy2].[A2] AS [C2],
[GroupBy2].[A3] AS [C3],
[GroupBy2].[A4] AS [C4]
FROM ( SELECT
[GroupBy1].[K1] AS [K1],
[GroupBy1].[K2] AS [K2],
SUM([GroupBy1].[A1]) AS [A1],
SUM([GroupBy1].[A2]) AS [A2],
SUM([GroupBy1].[A3]) AS [A3],
SUM([GroupBy1].[A4]) AS [A4]
FROM ( SELECT
[GroupBy1].[K1] AS [K1],
[GroupBy1].[K2] AS [K2],
CASE WHEN (1 = [GroupBy1].[K3]) THEN [GroupBy1].[A1] ELSE 0 END AS [A1],
CASE WHEN (2 = [GroupBy1].[K3]) THEN [GroupBy1].[A1] ELSE 0 END AS [A2],
CASE WHEN (52 = [GroupBy1].[K3]) THEN [GroupBy1].[A1] ELSE 0 END AS [A3],
CASE WHEN (53 = [GroupBy1].[K3]) THEN [GroupBy1].[A1] ELSE 0 END AS [A4]
FROM ( SELECT
[Join1].[K1] AS [K1],
[Join1].[K2] AS [K2],
[Join1].[K3] AS [K3],
SUM([Join1].[A1]) AS [A1]
FROM ( SELECT
[Extent1].[ProductId] AS [K1],
[Extent2].[Name] AS [K2],
DATEPART(wk, [Extent1].[DeliveryDate]) AS [K3],
[Extent1].[Quantity] AS [A1]
FROM [dbo].[Deliveries] AS [Extent1]
INNER JOIN [dbo].[Products] AS [Extent2] ON [Extent1].[ProductId] = [Extent2].[Id]
) AS [Join1]
GROUP BY [K1], [K2], [K3]
) AS [GroupBy1]
) AS [GroupBy1]
GROUP BY [K1], [K2]
) AS [GroupBy2]