2013-07-15 30 views
1

我有一个特定时间段(activationDate到endDate)的服务销售清单。我需要按月份(例如2012年4月)生成销售报告分组。对于每个月我想展示多少整月的使用和多少天。使用日期/月份分组处理列表中的数据

我的类:

public class SaleMonth 
{ 
    public DateTime MonthYear { get; set; }//.ToString("Y") 

    public int FullMonth { get; set; } 
    public int DaysMonth { get; set; } 

    public string TotalMonths { get { return String.Format("{0:N2}", 
            (((FullMonth * 30.5) + DaysMonth)/30.5)); } } 
} 

我曾尝试:

using (CompanyContext db = new CompanyContext()) 
{ 
    var saleList = db.MySales.ToList(); 
    DateTime from = saleList.Min(s => s.ActivationDate), 
     to = saleList.Max(s => s.EndDate); 

    for (DateTime currDate = from.AddDays(-from.Day + 1) 
           .AddTicks(-from.TimeOfDay.Ticks); 
       currDate < to; 
       currDate = currDate.AddMonths(1)) 
    { 
     var sm = new SaleMonth 
     { 
      MonthYear = currDate, 
      FullMonth = 0, 
      DaysMonth = 0 
     }; 

     var monthSell = saleList.Where(p => p.ActivationDate < currDate.AddMonths(1) 
               || p.EndDate > currDate); 
     foreach (var sale in monthSell) 
     { 
     if (sale.ActivationDate.Month == sale.EndDate.Month 
      && sale.ActivationDate.Year == sale.EndDate.Year) 
     {//eg 4/6/13 - 17/6/13 
      sm.DaysMonth += (sale.EndDate.Day - sale.ActivationDate.Day + 1); 
     } 
     else 
     { 
      if (sale.ActivationDate.Year == currDate.Year 
        && sale.ActivationDate.Month == currDate.Month) 
       sm.DaysMonth += (currDate.AddMonths(1) - sale.ActivationDate).Days; 
      else if (sale.EndDate.Year == currDate.Year 
        && sale.EndDate.Month == currDate.Month) 
       sm.DaysMonth += sale.EndDate.Day; 
      else if(sale.ActivationDate.Date <= currDate 
        && sale.EndDate > currDate.AddMonths(1)) 
       sm.FullMonth++; 
      }        
     } 
     vm.SaleMonthList.Add(sm); 
    } 
} 

我有我失去了一些东西的感觉,必须有一个更优雅的方式来做到这一点。

Here is a picture显示一些销售和从他们产生的报告。

回答

3

LINQ确实包含一种将数据分组的方法。

// group by Year-Month 
var rows = from s in saleList 
    orderby s.MonthYear 
    group s by new { Year = s.MonthYear.Year, Month = s.MonthYear.Month }; 

上面的语句将你的数据和组它由年月,这样它会为每个年月组合主键,创建一组的是:通过本声明考虑看看启动相应的SaleMonth项目进入该组。

当您掌握这一点时,下一步就是使用这些组计算每组中要计算的任何内容。所以,如果你只是希望总所有FullMonthsDaysMonths每个年月,你可以这样做:

var rowsTotals = from s in saleList 
    orderby s.MonthYear 
    group s by new { Year = s.MonthYear.Year, Month = s.MonthYear.Month } into grp 
    select new 
    { 
     YearMonth = grp.Key.Year + " " + grp.Key.Month, 
     FullMonthTotal = grp.Sum (x => x.FullMonth), 
     DaysMonthTotal = grp.Sum (x => x.DaysMonth) 
    }; 

编辑:

你在做什么,再次寻找后,我认为这样做会更有效率:

// populate our class with the time period we are interested in 
var startDate = saleList.Min (x => x.ActivationDate); 
var endDate = saleList.Max (x => x.EndDate); 

List<SaleMonth> salesReport = new List<SaleMonth>(); 
for(var i = new DateTime(startDate.Year, startDate.Month, 1); 
    i <= new DateTime(endDate.Year, endDate.Month, 1); 
    i = i.AddMonths(1)) 
{ 
    salesReport.Add(new SaleMonth { MonthYear = i }); 
} 

// loop through each Month-Year 
foreach(var sr in salesReport) 
{ 
    // get all the sales that happen in this month 
    var lastDayThisMonth = sr.MonthYear.AddMonths(1).AddDays(-1); 
    var sales = from s in saleList 
     where lastDayThisMonth >= s.ActivationDate, 
     where sr.MonthYear <= s.EndDate 
    select s; 

    // calculate the number of days the sale spans for just this month 
    var nextMonth = sr.MonthYear.AddMonths(1); 
    var firstOfNextMonth = sr.MonthYear.AddMonths(1).AddDays(-1).Day; 
    sr.DaysMonth = sales.Sum (x => 
     (x.EndDate < nextMonth ? x.EndDate.Day : firstOfNextMonth) - 
      (sr.MonthYear > x.ActivationDate ? 
      sr.MonthYear.Day : x.ActivationDate.Day)); 

    // how many sales occur over the entire month 
    sr.FullMonth = sales.Where (x => x.ActivationDate <= sr.MonthYear && 
           nextMonth < x.EndDate).Count(); 
} 
+0

真的谢谢你!我喜欢填充日期的方式,然后通过它们并相应地获取数据。 除了根据给定的日期检索所有销售对我其他地方非常有用 - 单击报告中每行的“详细信息”。 所以+1两次=) – oCcSking

+0

嗨Ijust在Sum函数上得到这个错误..“只有无参数的构造函数和初始化程序在linq中支持实体”我尝试将addMonth(1)更改为外部var - monthLetter,但是stil get这个例外“你有空闲吗? – oCcSking

+1

@oCcSking,对于Linq-to-Entities,您必须删除所有正在创建的无参数构造函数。如果你看看我的编辑,我已经改变了应该让你再次去的所有查询,并且至少会让你运行来进行调整。 –

1

我同意Rem先生的说法,LINQ是要走的路。由于你的计算是复杂的,我想创建一个辅助功能,以及:

Func<DateTime, DateTime, bool> matchMonth = (date1, date2) => 
    date1.Month == date2.Month && date1.Year == date2.Year; 

然后,您可以创建在计算中使用的函数:

Func<MySale, DateTime, int> calcDaysMonth = (sale, currDate) => 
{ 
    if (matchMonth(sale.ActivationDate, sale.EndDate)) 
    { 
      return (sale.EndDate.Day - sale.ActivationDate.Day + 1); 
    } 
    else 
    { 
     if (matchMonth(sale.ActivationDate, currDate)) 
      return (currDate.AddMonths(1) - sale.ActivationDate).Days; 
     else if (matchMonth(sale.EndDate, currDate) 
      return sale.EndDate.Day; 
     else 
      return 0; 
    } 
} 

如果用雷姆的先生结合这些技术,你应该有一个很好的,可读的,简洁的函数来为你收集数据,并且很容易测试和调试。

+0

这是真实的,并在重用方面更优雅。我是在时间和空间 复杂性或改变像LINQ或一些其它的东西可爱:) 10倍梅索德反正方面寻找性能更改变的事实。 。 – oCcSking

相关问题