2016-11-13 96 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]