2016-11-13 90 views
0

我有这样的实体:我该如何改进这个Linq查询(一种旋转)?

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

我不明白你的逻辑或你的代码。你说你想按周显示交货。你能详细说明吗?什么是'Wk1,Wk2等'? –

+0

我正在显示一个包含53列的表格,第一列是ProductName,接下来的52列是从week1(wk1)到week52(wk52)一年中的几周。在上面的查询中,我删除了一些行以显示较小的查询。 –

+0

哇,你检查了生成的SQL吗?由于关于分组结果的52个Where语句,我期望它是一个怪物。你用什么ORM btw? –

回答

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

我会做在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]