2009-06-19 12 views
1

Ich habe vor kurzem eine LINQ-Abfrage geschrieben, um eine Dictionary zu erhalten, die die letzten 6 Monate Platzierungsbeträge enthält.Wie kann ich diese LINQ-Abfrage sauberer machen?

Es wird ein Dictionary von Monat Zeichenfolge - Dezimalbetrag Paare zurückgegeben.

Es scheint eine Art von cluddyy. Irgendwelche von euch LINQ-Meistern da draußen, die mir helfen können, das umzuformulieren, um ein bisschen sauberer zu machen?

/// <summary> 
/// Gets the last 6 months of Placement History totalled by Month 
/// for all Agencies 
/// </summary> 
/// <returns></returns> 
public Dictionary<string, decimal> getRecentPlacementHistory() 
{ 
    var placementHistoryByMonth = new Dictionary<string, decimal>(); 

    using (DemoLinqDataContext db = new DemoLinqDataContext()) 
    { 
     for (int i = 0; i < 6; i++) 
     { 
      Decimal monthTotal = 
       (from a in db.Accounts 
       where 
       (a.Date_Assigned.Value.Month == DateTime.Now.AddMonths(-i).Month && 
        a.Date_Assigned.Value.Year == DateTime.Now.AddMonths(-i).Month) 
       select a.Amount_Assigned).Sum(); 
      String currentMonth = DateTime.Now.AddMonths(-i).ToString("MMM"); 

      placementHistoryByMonth.Add(currentMonth, monthTotal); 
     } 
     return placementHistoryByMonth; 
    } 
} 

Antwort

5

Erstes Problem:

where (a.Date_Assigned.Value.Month == DateTime.Now.AddMonths(-i).Month && 
     a.Date_Assigned.Value.Year == DateTime.Now.AddMonths(-i).Month) 

Ist dieser Ausdruck nicht mit .year enden anstatt .Month? Sicher werden Sie selten ein Jahr mit einem Wert von 1-12 bekommen ...

Ich würde die Idee des "aktuellen Monats" extrahieren, wie Sie es viel verwenden. Beachten Sie, dass Sie auch die aktuelle Zeit mehrmals nehmen, die ungerade Ergebnisse geben könnte, wenn sie am Ende eines Monats um Mitternacht läuft ...

public Dictionary<string, decimal> getRecentPlacementHistory() 
{ 
    var placementHistoryByMonth = new Dictionary<string, decimal>(); 
    using (DemoLinqDataContext db = new DemoLinqDataContext()) 
    { 
     DateTime now = DateTime.Now; 

     for (int i = 0; i < 6; i++) 
     { 
      DateTime selectedDate = now.AddMonths(-i); 

      Decimal monthTotal = 
       (from a in db.Accounts 
       where (a.Date_Assigned.Value.Month == selectedDate.Month && 
         a.Date_Assigned.Value.Year == selectedDate.Year) 
       select a.Amount_Assigned).Sum(); 

      placementHistoryByMonth.Add(selectedDate.ToString("MMM"), 
             monthTotal); 
     } 
     return placementHistoryByMonth; 
    } 
} 

Ich weiß, es ist wahrscheinlich die Schleife, die Sie versuchten, beseitigen, abschütteln. Sie könnten versuchen, die oberen und unteren Grenzen der Daten für das gesamte Los auszuarbeiten und dann innerhalb der relevanten Grenzen nach dem Jahr/Monat a.Date_Assigned zu gruppieren. Um ehrlich zu sein, wird es nicht viel schöner sein. Wohlgemerkt, das wäre nur eine Abfrage an die Datenbank, wenn Sie es schaffen könnten.

+1

selectedDate.Month.Year macht nicht viel Sinn ... Tippfehler? ;) – em70

+0

@ Jon Skeet, Wie kann ich mit der Situation umgehen, wo der Monat Januar ist. Sobald wir Monate vom aktuellen Datum subtrahieren, wird das Jahr nicht mehr übereinstimmen und diese Methode wird fehlschlagen. Ich versuche herauszufinden, wie ich das schaffen kann, aber immer noch nicht für JEDEN Januar. –

+0

Ja, darüber habe ich mich gewundert. Er verwendet "selectedDate.Month.Year", um zu verhindern, dass Daten aus allen ähnlichen Monaten über die Jahre hinweg erfasst werden. Wenn die Datumsbereichsschleife jedoch genügend Monate subtrahiert, wird sich das Jahr ändern und es wird nicht funktionieren. Wie würdest du das schaffen? – KingNestor

0

Wenn Sie nicht besorgt über Monate ohne Daten fehlen, dann hatte ich ein ähnliches Problem, wo ich das folgende tat: (auf Ihre Variablen übersetzt) ​​

DateTime startPeriod = 
    new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(-6); 

    var query1 = from a in db.Accounts where a.Date_Assigned >= startPeriod 
group a by new { a.Date_Assigned.Year ,a.Date_Assigned.Month } into result 
select new 
{ 
    dt = new DateTime(result.Key.Year, result.Key.Month , 1), 
    MonthTotal = result.Sum(i => i.Amount_Assigned) 
} ;    

    var dict = query1.OrderBy(p=> p.dt).ToDictionary(n => n.Dt.ToString("MMM") , n => n.MonthTotal); 
2

Usegroup von

DateTime now = DateTime.Now; 
DateTime thisMonth = new DateTime(now.Year, now.Month, 1); 

Dictionary<string, decimal> dict; 
using (DemoLinqDataContext db = new DemoLinqDataContext()) 
{ 
    var monthlyTotal = from a in db.Accounts 
     where a.Date_Assigned > thisMonth.AddMonths(-6) 
     group a by new {a.Date_Assigned.Year, a.Date_Assigned.Month} into g 
     select new {Month = new DateTime(g.Key.Year, g.Key.Month, 1), 
        Total = g.Sum(a=>a.Amount_Assigned)}; 

    dict = monthlyTotal.OrderBy(p => p.Month).ToDictionary(n => n.Month.ToString("MMM"), n => n.Total); 
} 

Keine Schleife benötigt!

+0

Nizza! Es kann sinnvoll sein, nach (Jahr * 100 + Monat) zu gruppieren. Precompute "thisMonth.AddMonths (-6)" – Ray

Verwandte Themen