0

即使某些月份不包含任何数据,我也希望能够按月份对所有数据进行分组。此时,我可以分组,但返回的数据只包含月份数据。

这是我的代码的样子:

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。

我怎样才能做到这一切而无需在评论下方执行代码?

4

2 回答 2

1

我还没有编译和调试这个,但它应该让我知道我认为你可以如何解决你的问题。我用来Enumerable.Range为您需要的月份生成一组占位符。然后我不得不在左加入和合并之间做出选择,placeHolders或者data只是连接遗漏。

我还重新修改了问题中的代码以帮助我理解它。

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();
}

连接遗漏的方法几乎可以保证以不合逻辑的顺序返回数据,但是,除非您使用 order by 子句,否则无论如何您都没有 garauntees。

于 2012-07-25T16:49:08.230 回答
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 型号,您必须尝试一下,看看是否需要替换new DateTimeEntityFunctions.CreateDateTime.

于 2012-07-25T17:30:17.700 回答