我有这个实体:
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个样本行在传递数据库表中,并且我有填充这种方式来获取数据不是最好的一个。
查询正在运行,我只想知道您是否有更好的方法来编写此类查询。
答案 0 :(得分:1)
我看到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),
...
答案 1 :(得分:1)
我会在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()之上的所有内容都作为1个针对数据库的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]