根据时间框架和按月分组获得结果

本文关键字:结果 时间 框架 | 更新日期: 2023-09-27 18:08:28

我有一个包含许多表的数据库。其中一个表VersionBuild包含一个日期列。我得到的结果使用以下查询,只选择记录出现在一定的时间范围内(如。最近6个月)

我使用的代码如下

DateTime startDate = DateTime.Now.AddMonths(-(timeFrame));
var grouped = db.VersionBuilds
                .Where(r => r.product_id == id && r.date > startDate)
                .GroupBy(r => new { r.date.Year, r.date.Month })
                .Select(r => new { 
                    month = getMonthName(r.Key.Month), 
                    totalIssues = r.Sum(zz => zz.AcrolinxReport.total_issues) 
                });
return grouped;

代码的一个问题是,如果没有特定月份的记录,它会忽略它。我在图表中显示返回的信息,因此这在数据中留下了空白。例如,如果我在5月和6月有记录,它将返回5月和6月的数据,但我想要的是返回指定时间范围内所有月份的数据,无论是否有任何数据。

根据时间框架和按月分组获得结果

我相信这对你有用。没有数据很难测试,但我认为你应该没有任何问题。

// Assume 'timeframe' is a positive integer.
// Get the start date.
DateTime startDate = DateTime.Now.AddMonths(-timeframe);
// Generate a list of months (year and month, actually) beginning 
// with the month of 'startDate'.
var months =
    Enumerable
    .Range(0, timeframe)
    .Select(x => startDate.AddMonths(x))
    .Select(x => new { x.Year, x.Month });
// Create builds query.
var builds =
    db.VersionBuilds
    .Where(r => r.product_id == id && r.date > startDate)
    .GroupBy(r => new { r.date.Year, r.date.Month })
    .Select(r => new { 
        Month = r.Key.Month,
        Year = r.Key.Year,
        TotalIssues = r.Sum(zz => zz.AcrolinxReport.total_issues));
// Join 'months' on 'builds'
var grouped =
    months
    .GroupJoin(
        builds.AsEnumerable(),
        date => date,
        build => new { build.Year, build.Month },
        (date, buildGroup) => new { 
            date.Year, 
            date.Month, 
            TotalIssues = buildGroup.Sum(x => x.TotalIssues) })
    .OrderBy(x => x.Year)
    .ThenBy(x => x.Month)
    .Select(x => new { Month = getMonth(x.Month), x.TotalIssues });

你可以尝试这样做:

首先,我们创建一个包含给定时间范围内所有月份的列表例如,如果我们现在运行这个并将timeFrame设置为3,那么该列表将包含以下日期时间

  • 2015-08-15…
  • 2015-07-15…
  • 2015-06-15

代码如下:

var monthsInTimeFrame = new List<DateTime>();
for(int i = timeFrame; i>=0 ; i--)
{ 
    monthsInTimeFrame.Add(DateTime.Now.AddMonths(-i));
}

然后你继续用你已经得到的方式获取你的数据,但有一个小的变化。而不是创建一个对象列表匿名类型,创建命名类型的对象列表。我取了一个模糊的名字:Data。你想取什么名字都行。此外,这种类型将具有两个额外的属性,一个是Year,另一个是Month。我们需要它们,以便确定预期月份中的特定月份是否在列表中。

DateTime startDate = DateTime.Now.AddMonths(-(timeFrame));
var grouped = db.VersionBuilds
                .Where(r => r.product_id == id && r.date > startDate)
                .GroupBy(r => new { r.date.Year, r.date.Month })
                .Select(r => new Data
                { 
                    Year = r.Key.Name,
                    Month = r.Key.Month,
                    MonthName = getMonthName(r.Key.Month), 
                    TotalIssues = r.Sum(zz => zz.AcrolinxReport.total_issues) 
                }).ToList();

注意,我们必须在查询结束时调用ToList,因为下面我们将使用Add方法来添加缺失的月份。

最后,我们必须遍历monthsInTimeFrame的项:

foreach(var month in monthsInTimeFrame)
{
    // If there isn't any item in the list called
    // grouped with the same year and month of the current month,
    // we have to add a new item in this list       
    if(!grouped.Any(item=>item.Year==month.Year &&
                          item.Month==month.Month)) 
        grouped.Add(new Data
        { 
            Year = month.Year, 
            Month = month.Month,
            MonthName = getMonthName(month.Month), 
            TotalIssues = 0 
        });
}
return grouped;

Data类的定义可以是这样的:

public class Data
{
    public int Year { get; set; }
    public int Month { get; set; }
    public string MonthName { get; set; }
    public int TotalIssues { get; set; }
}