C# 基于数据实体框架和LINQ的数据分组

C# 基于数据实体框架和LINQ的数据分组,c#,.net,entity-framework,linq,C#,.net,Entity Framework,Linq,我的数据库中有一系列分析事件,我想将这些数据按日期分组发送到我的客户端应用程序 数据库中的数据看起来像这样(但有数百条记录): 我想做的是返回所有“社交”“点击”的计数,但按月计算,因此如下所示: [ { "name": "socialclicks", "series": [ { "count": 259, "name": "Jan" }, { "count": 0, "nam

我的数据库中有一系列分析事件,我想将这些数据按日期分组发送到我的客户端应用程序

数据库中的数据看起来像这样(但有数百条记录):

我想做的是返回所有“社交”“点击”的计数,但按月计算,因此如下所示:

[
  {
    "name": "socialclicks",
    "series": [
      {
        "count": 259,
        "name": "Jan"
      },
      {
        "count": 0,
        "name": "Feb"
      },
      {
        "count": 52,
        "name": "Mar"
      }
      ... etc, etc up to Dec <====
    ]
  }
]
[
{
“名称”:“socialclicks”,
“系列”:[
{
“计数”:259,
“姓名”:“Jan”
},
{
“计数”:0,
“姓名”:“二月”
},
{
“计数”:52,
“名称”:“Mar”
}

…etc,etc截至12月首先要做的是根据您感兴趣的两个属性对所有数据进行分组

  • 事件
  • 类别
例如:

 var partialResult = entries.GroupBy(x => new {
       x.Event,
       x.Category
    });
从这里开始,当您投影结果时,您可以按月份和年份再次分组。-用于演示的匿名对象,但您可以根据需要轻松地将其定义为结构/类:

var result = entries.GroupBy(x => new {
       x.Event,
       x.Category
    }).Select(g => new {
       g.Key.Event,
       g.Key.Category,
       Series = g.GroupBy(x => new {x.DateAdded.Month, x.DateAdded.Year})
                 .Select(i => new{
                         i.Key.Month,
                         i.Key.Year,
                         Count = i.Count()
                }).ToArray()
    });

foreach(var item in result)
{
    Console.WriteLine($"Event:{item.Event} Category:{item.Category}");
    foreach(var serie in item.Series)
        Console.WriteLine($"\t{CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(serie.Month)}{serie.Year} Count={serie.Count}");
}

编辑:为满足您的要求,请执行以下操作:

如果月份不存在,则返回0

你需要增加一些复杂性。首先是一个可以计算出两个日期之间所有月/年组合的方法

private static IEnumerable<(int Month, int Year)> MonthsBetween(
        DateTime startDate,
        DateTime endDate)
{
    DateTime iterator;
    DateTime limit;

    if (endDate > startDate)
    {
        iterator = new DateTime(startDate.Year, startDate.Month, 1);
        limit = endDate;
    }
    else
    {
        iterator = new DateTime(endDate.Year, endDate.Month, 1);
        limit = startDate;
    }

    var dateTimeFormat = CultureInfo.CurrentCulture.DateTimeFormat;
    while (iterator < limit)
    {
        yield return (iterator.Month,iterator.Year);                
        iterator = iterator.AddMonths(1);
    }
}

实例:

您在同一年创建的条目是否可能重复?不幸的是,我只想返回过去12个月的条目,但我想稍后再处理该条目!!也就是说,如果是2018年8月,我将从2017年8月到2018年8月返回,任何为空的条目都返回为0。您可以更新你问这些额外的要求,否则我不会把他们看作问题的范围。谢谢,已经更新我的问题席。魔术::非常感谢,这是更好的!@ dBOI没有PROBS。只是意识到这不会给你几个月不存在你的数据。问题?理想的是我希望有几个月与在过去12个月内,如果不存在,则返回0,以便用户知道其为0(如果有意义)?有意义,您有2个选项。1)将此视为UI问题并在那里处理,或2)将结果加入到预先计划的月份集。2很灵活,但可以。如果需要,我可以更新答案是的,我认为可以更好地处理it服务器端的问题-感谢您的帮助,非常感谢您的帮助
var result = entries.GroupBy(x => new {
       x.Event,
       x.Category
    }).Select(g => new {
       g.Key.Event,
       g.Key.Category,
       Series = g.GroupBy(x => new {x.DateAdded.Month, x.DateAdded.Year})
                 .Select(i => new{
                         i.Key.Month,
                         i.Key.Year,
                         Count = i.Count()
                }).ToArray()
    });

foreach(var item in result)
{
    Console.WriteLine($"Event:{item.Event} Category:{item.Category}");
    foreach(var serie in item.Series)
        Console.WriteLine($"\t{CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(serie.Month)}{serie.Year} Count={serie.Count}");
}
private static IEnumerable<(int Month, int Year)> MonthsBetween(
        DateTime startDate,
        DateTime endDate)
{
    DateTime iterator;
    DateTime limit;

    if (endDate > startDate)
    {
        iterator = new DateTime(startDate.Year, startDate.Month, 1);
        limit = endDate;
    }
    else
    {
        iterator = new DateTime(endDate.Year, endDate.Month, 1);
        limit = startDate;
    }

    var dateTimeFormat = CultureInfo.CurrentCulture.DateTimeFormat;
    while (iterator < limit)
    {
        yield return (iterator.Month,iterator.Year);                
        iterator = iterator.AddMonths(1);
    }
}
var dateRangeStart = DateTime.Parse("2006-01-01");
var dateRangeEnd = DateTime.Parse("2007-01-01");
var monthRange = MonthsBetween(dateRangeStart,dateRangeEnd);

var results = entries.Where(e => e.DateAdded>=dateRangeStart && e.DateAdded<dateRangeEnd)
     ..... etc
foreach(var item in results)
{
    Console.WriteLine($"Event:{item.Event} Category:{item.Category}");

    var joinedSeries = from month in monthRange
                        join serie in item.Series
                        on new{month.Year, month.Month} equals new {serie.Year, serie.Month} into joined
                        from data in joined.DefaultIfEmpty()
                        select new {
                            Month = data == null ? month.Month : data.Month,
                            Year = data == null ? month.Year : data.Year,
                            Count = data == null ? 0 : data.Count
                        };


foreach(var serie in joinedSeries)
    Console.WriteLine($"\t{CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(serie.Month)}{serie.Year} Count={serie.Count}");
}