2012-07-25 70 views
0

我希望能够将我的所有数据按月分组,即使有些月份不包含任何数据。此时,我可以分组,但返回的数据只包含数据。Linq to Entity,选择无价值团体

下面是我的代码如下所示:

var twelveMonthAgo = date.AddMonths(-12).Date; 
var twelveMonthAgoFirstOfMonth = new DateTime(twelveMonthAgo.Year, twelveMonthAgo.Month, 1, 0, 0, 0, 0); 

var data = (from i in Database.Users 
      where i.RegisterDate >= twelveMonthAgoFirstOfMonth 
      group i by new {y=i.RegisterDate.Year,m = i.RegisterDate.Month} into g 
      select new UserStatistic{ Date = EntityFunctions.CreateDateTime(g.Key.y, g.Key.m, 1, 0, 0, 0) 
             , UserCount = g.Count(o => o.Id) 
            }); 

//The code below is what I would like to remove           
var toReturn = new List<UserStatistic>(); 
var allData = data.ToList(); 
DateTime datei = twelveMonthAgoFirstOfMonth; 
while (datei.Year<= date.Year && datei.Month<=date.Month){ 
    var info = allData.SingleOrDefault(x => x.Date.HasValue && x.Date.Value.Year == datei.Year && x.Date.Value.Month == datei.Month); 
    toReturn.Add(info ?? new UserStatistic { Date = datei, UserCount = 0, PaymentPaid = 0 }); 
    datei = datei.AddMonths(1); 
} 
return toReturn.AsQueryable(); 

正如你可以看到,注释下的代码建立过去12个月的收集和检查,如果一些数据已经从数据库中,并填写如果存在的话收集集合,否则将其设为0.

我该怎么做,而不必在评论下面做代码?

+0

是“数据”中的第一个月还是1月('1')还是第一年?同样,上个月应该是去年的12月份('12'),还是上个月的'data'? – Jodrell 2012-07-25 15:55:50

+1

您需要将日期的左外连接执行到聚合值。一个group将总会忽略不分组的值。 – casperOne 2012-07-25 16:00:16

+0

@Jodrell日期范围并不重要,这可能会改变。我想要的是获得最后x个月的数据。 – 2012-07-25 16:04:26

回答

1

这是一个使用一组一些代码加入到一个子查询得到你想要的结果:

DateTime date = DateTime.Today; 
DateTime firstOfMonth = new DateTime(date.Year, date.Month, 1); 
DateTime twelveMonthAgoFirstOfMonth = firstOfMonth.AddMonths(-12); 

// Generate a collection of the months and years for the last 12 months 
var monthYears = Enumerable.Range(-12, 12).Select(monthOffset => { DateTime monthDate = firstOfMonth.AddMonths(monthOffset); return new { y = monthDate.Year, m = monthDate.Month }; }); 

// Go through the list of months and years and join them to the users retrieved from the database in the subquery. 
var data = from monthYear in monthYears 
      join i in (from i in Database.Users 
         where i.RegisterDate >= twelveMonthAgoFirstOfMonth && i.RegisterDate < firstOfMonth 
         select i) on monthYear equals new { y = i.RegisterDate.Year, m = i.RegisterDate.Month } into gj 
      select new UserStatistic() { Date = new DateTime(monthYear.y, monthYear.m, 1), UserCount = gj.Count() }); 

这也可以表示为一个左外子查询组加入:

DateTime date = DateTime.Today; 
    DateTime firstOfMonth = new DateTime(date.Year, date.Month, 1); 
    DateTime twelveMonthAgoFirstOfMonth = firstOfMonth.AddMonths(-12); 
    var monthYears = Enumerable.Range(-12, 12).Select(monthOffset => { DateTime monthDate = firstOfMonth.AddMonths(monthOffset); return new { y = monthDate.Year, m = monthDate.Month }; }); 

    var data = (from monthYear in monthYears 
       join i in (from i in Database.Users 
          where i.RegisterDate >= twelveMonthAgoFirstOfMonth && i.RegisterDate < firstOfMonth 
          group i by new {y = i.RegisterDate.Year, m = i.RegisterDate.Month} into g 
          select new { Key = g.Key, UserCount = g.Count() }) on monthYear equals i.Key into j 
       from k in j.DefaultIfEmpty() 
       select new UserStatistic() { Date = new DateTime(monthYear.y, monthYear.m, 1), UserCount = k != null ? k.UserCount : 0 }); 

由于我没有EF模型,您必须尝试一下,看看您是否需要用EntityFunctions.CreateDateTime替换new DateTime

+0

你的第二个例子正是我进入它的!它运作良好。非常感谢您的意见。 – 2012-07-25 18:49:09

1

我还没有编译和调试,但它应该给我一个想法,我认为你可以解决你的问题。我使用Enumerable.Range为您需要的月份生成一组占位符。然后我必须选择左边加入placeHoldersdata并合并,或者只是将这些遗漏连接起来。

我也重新格式化了这个问题的代码,以帮助我理解它。

IQueryable<UserStatistic> GetPastMonths(int months) 
{  
    var limitDay = date.AddMonths(-months).Date; 
    var limit = new DateTime(limitDay.Year, limitDay.Month, 1, 0, 0, 0, 0); 

    var placeHolders = Enumerable.Range(0, months + 1) 
     .Select(m => 
      new UserStatistic 
       { 
        Date = limit.AddMonths(-m), 
        UserCount = 0 
       }); 

    var data = Database.Users 
     .Where(i => i.RegisterDate >= limit) 
     .GroupBy(i => new {y=i.RegisterDate.Year, m = i.RegisterDate.Month}) 
     .Select(g => 
      new UserStatistic 
       { 
        Date = EntityFunctions.CreateDateTime(
          g.Key.y, 
          g.Key.m, 
          1, 
          0, 
          0, 
          0), 
        UserCount = g.Count(o => o.Id) 
       }); 

    return data.Concat(placeHolders 
     .Where(p => !data.Any(d => d.Date == p.Date))) 
     .AsQueryable(); 
} 

的cocatenating的ommissions方法几乎garaunteed给数据传回在一个不合逻辑的订单,但,你有没有garauntees反正除非你子句中使用的命令。

+0

这看起来接近我现在正在试验的东西。让我完成我的例子,我更仔细地看待你的例子。谢谢 – 2012-07-25 17:19:21