簡體   English   中英

基於日期實體框架和LINQ的數據分組

[英]Grouping data based on date entity framework and LINQ

我的數據庫中有一系列分析事件,我想將此按日期分組的數據發送到我的客戶端應用程序。

來自數據庫的數據看起來像這樣(但有數百條記錄):

[
  {
    "DateAdded": "2006-12-30 00:38:54",
    "Event": "click",
    "Category": "externalWebsite"
  },
  {
    "DateAdded": "2006-07-20 00:36:44",
    "Event": "click",
    "Category": "social"
  },
  {
    "DateAdded": "2006-09-20 00:36:44",
    "Event": "click",
    "Category": "social"
  },
  {
    "DateAdded": "2006-09-22 00:12:34",
    "Event": "load",
    "Category": "profile"
  }
]

我想要做的是返回所有說“社交”“點擊”的計數,但按月返回它看起來像這樣:

[
  {
    "name": "socialclicks",
    "series": [
      {
        "count": 259,
        "name": "Jan"
      },
      {
        "count": 0,
        "name": "Feb"
      },
      {
        "count": 52,
        "name": "Mar"
      }
      ... etc, etc up to Dec <====
    ]
  }
]

因此,我一直在嘗試使用特定用戶的 id 獲取與特定用戶關聯的所有記錄。 這很簡單。

現在我需要將它們的記錄拆分為顯示從當月開始的最后 12 個月的月度計數(如果該月不存在,則返回 0) - 這被證明是復雜和困難的。

我的方法是這樣的:

var records = context.records.where(r => r.Id = userId).ToList();
var jan
var feb
var mar
var apr
... etc, etc

for (int i = 0; i < records.Count ; i++)
{
    if (record.DateAdded > "2005-12-31 00:00.00" && record.DateAdded < "2006-01-31 00:00.00") {
       jan++;
    }

    if (record.DateAdded > "2006-01-31 00:00.00" && record.DateAdded < "2006-02-28 00:00.00") {
       feb++;
    }

    ...etc, etc
}

然后我使用這些變量來計算和硬編碼返回數據的名稱。

正如你所看到的,有很多等等,因為代碼變得荒謬了!

必須有一種更簡單的方法來做到這一點,但我似乎找不到一個!

任何援助將不勝感激。

謝謝

首先要做的是按您感興趣的 2 個屬性對所有數據進行分組

  • 事件
  • 類別

例子:

 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

您需要添加一些復雜性。 首先是一種可以計算出 2 個日期之間的所有月/年組合的方法。

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

然后,在輸出結果時,您需要有效地對年/月列表進行左連接。 出於某種原因,使用查詢語法比使用 lambda 更容易。

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

實例: https : //dotnetfiddle.net/K7ZoJN

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM