2013-11-25 44 views
0

我將不勝感激關於改善這個linq查詢的任何建議。我正在查詢一張發票清單,目的是找到每月發票總額最高的客戶。然後我想顯示年,月,客戶和發票總額。如何改進這個LINQ查詢?

發票:

public class Invoice 
{ 
    public string Customer { get; set; } 
    public DateTime Date { get; set; } 
    public double Amount { get; set; } 
} 

數據上下文創建發票清單:

public class DataContext 
    {     
     private List<Invoice> _invoices; 
     private List<string> _customers; 

     public List<Invoice> Invoices 
     { 
      get 
      { 
       if (_invoices == null) 
       { 
        _customers = new List<string>(){ "Jim", "John", "Jeff", "Joe", "Jack"}; 
        _invoices = new List<Invoice>(); 
        Random random = new Random(); 

        for (int i = 0; i < 1000; i++) 
        { 
         _invoices.Add(new Invoice() { 
          Customer = _customers[random.Next(0, 5)], 
          Date = new DateTime(random.Next(2010, 2015), random.Next(1, 13), random.Next(1, 20)), 
          Amount = random.Next(1,1000) 
         });      
        } 
       } 
       return _invoices; 
      } 
     } 
    } 

查詢:

DataContext context = new DataContext(); 

var invoiceTotalsByMonth = from invoice in context.Invoices 
          group invoice by invoice.Date.Year into yearGroup 
          orderby yearGroup.Key 
          select new 
          { 
           Year = yearGroup.Key, 
           Months = from year in yearGroup 
              group year by year.Date.Month into monthGroup 
              orderby monthGroup.Key 
              select new 
              { 
               Month = monthGroup.Key, 
               CustomerTotals = from month in monthGroup 
                   group month by month.Customer into customerGroup                  
                   select new 
                   { 
                    Customer = customerGroup.Key, 
                    Total = customerGroup.Sum(i=>i.Amount) 
                   } 
                } 
            }; 

      foreach (var year in invoiceTotalsByMonth) 
      { 
       Response.Write(year.Year + "<br/>"); 

       foreach (var month in year.Months) 
       { 
        var maxCustomer = month.CustomerTotals.First(i => i.Total == month.CustomerTotals.Max(j => j.Total)); 

        Response.Write(month.Month + ": " + maxCustomer.Customer + " - " + maxCustomer.Total.ToString("c") + "<br/>"); 
       } 
      }  

謝謝您的建議。

+3

這可能更適合[codereview.se] –

+0

謝謝。我對此並不熟悉,但我會研究它。有沒有辦法將這篇文章轉移到Code Review? –

+0

不用擔心!點擊問題底部附近的「標誌」,然後選擇「其他」,並說您的問題可能更適合代碼審查。版主會盡快查看。 –

回答

2

怎麼樣:

DataContext context = new DataContext(); 

var invoiceTotalsByMonthQuery = from i in context.Invoices 
           group i by new { i.Date.Year, i.Date.Month } into g 
           select new 
           { 
            Year = g.Key.Year, 
            Month = g.Key.Month, 
            Customer = g.GroupBy(x => x.Customer) 
               .Select(x => new { Name = x.Key, Total = x.Sum(y => y.Amount)}) 
               .OrderByDescending(x => x.Total) 
               .First() 
           }; 

var invoiceTotalsByMonth = invoiceTotalsByMonthQuery.OrderBy(x => x.Year) 
                .ThenBy(x => x.Month); 

foreach(var item in invoiceTotalsByMonth) 
{ 
    Console.WriteLine("{0}/{1} - {2} ({3})", item.Month, item.Year, item.Customer.Name, item.Customer.Total); 
} 

一個忠告:這是可能更好地使用OrderBy + First而不是First + Max與最大屬性值來尋找項目。

+0

謝謝。我正在尋找這個解決方案,通過匿名類型分組來消除嵌套組。但是,爲什麼OrderBy + First比First + Max好? –

+0

好問題。它絕對更具可讀性。它表現更好嗎?我不確定,但我會測試一下。解決這類問題的最好方法是使用'MaxBy'(moreLINQ),但它不是標準LINQ的一部分。 – MarcinJuraszek

+0

性能似乎幾乎相等,幾ms內。但我更喜歡你的可讀性和簡潔性,而不是我正在使用的凌亂的嵌套分組。謝謝! –