LINQ group by date – 包括空日,不使用join

使用C#,NHibernate,NHibernate到LINQ。 使用NHibernate到LINQ,我没有JOINfunction。 我也不能使用QueryOver。

我有一个LINQ查询,计算潜在客户和销售额。 此表仅在新的销售线索或销售完成时创建,因此有些日子没有插入行。 执行以下查询有效

var query3 = query2.AsEnumerable() .Where(x => x.Created = fromDate.Value) .GroupBy(x => x.Created.Date) .Select(g => new ReferrerChart { Date = g.Key.Date, LeadsCount = g.Count(x => !x.IsSale), SalesCount = g.Count(x => x.IsSale) }); 

但有些日期不在那里(日期有0个线索和销售)。

如何包含这些日期并让他们设置LeadsCount = 0和SalesCount = 0而不使用join?

编辑:

最终结果有效:

 var selectedFromDate = fromDate.Value; var selectedToDate = toDate.Value; var selectedDates = Enumerable.Range(0, 1 + selectedToDate.Subtract(selectedFromDate).Days) .Select(offset => new ReferrerChart { Date = selectedFromDate.AddDays(offset), LeadsCount = 0, SalesCount = 0 }) .ToList(); var query3 = Find(x => x.Source == "UserRef").AsEnumerable() .Where(x => x.Created = fromDate.Value) .GroupBy(x => x.Created.Date) .Select(g => new ReferrerChart { Date = g.Key.Date, LeadsCount = g.Count(x => !x.IsSale), SalesCount = g.Count(x => x.IsSale) }).ToList(); var result = query3.Union( selectedDates .Where(e => !query3.Select(x => x.Date).Contains(e.Date))) .OrderBy(x => x.Date); 

您可以使用在内存中创建的虚拟项目来Union()查询中的数据。 例如:

 var query4 = query3.ToList(); // Prevent multiple execution. var startDate = DateTime.Today.AddDays(-99); var emptyData = Enumerable.Range(1,100).Select (i => new ReferrerChart { Date = startDate.AddDays(i), LeadsCount = 0, SalesCount = 0 }); var result = query4 .Union( emptyData .Where(e => !query4.Select(x => x.Date).Contains(e.Date))) .OrderBy(x => x.Date); 

我将在LINQ查询中更改两件事,我将包括空日期

.Where(x => x.Created <= toDate.Value && x.Created >= fromDate.Value)

变得像

.Where(x => x.Created.Date == null || (x.Created <= toDate.Value && x.Created >= fromDate.Value))

我的另一个指针是你的.GroupBy需要一个x.Created.Date,使用IsNull或类似的函数将这里的值设置为一个值,无论该条目是否为Null

例如(x.Created == null ? "" : x.Created.ToString("yyyyMMdd"))

(我道歉但此时我不在我的开发PC上,所以无法明确说明正确的代码)

通过为IEnumerable> (从GroupBy返回的类型)实现扩展方法,有一种很好的方法。 以我的拙见,这是最好的方法,原因有很多:

  • 不重新计算正在填充的结果集( .ToList()也会实现这一点,但是以急切的评估为代价),
  • 保持GroupBy延迟评估(延期执行),
  • 单行友好(可以在流畅的LINQ查询中链接),
  • 通用,可重复使用,
  • 优雅,易读。

履行

 public static IEnumerable> Fill(this IEnumerable> groups, IEnumerable filling) { List keys = filling.ToList(); foreach (var g in groups) { if(keys.Contains(g.Key)) keys.Remove(g.Key); yield return g; } foreach(var k in keys) yield return new EmptyGrouping(k); } class EmptyGrouping : List, IGrouping { public TKey Key { get; set; } public EmptyGrouping(TKey key) { this.Key = key; } } 

样品用法

 Random rand = new Random(); var results = Enumerable.Repeat(0, 5) // Give us five .Select(i => rand.Next(100)) // Random numbers 0 - 99 .GroupBy(r => r.Dump("Calculating group for:") / 10) // Group by tens (0, 10, 20, 30, 40...) .Fill(Enumerable.Range(0, 10)) // Fill aby missing tens .OrderBy(g => g.Key); // Sort @"Anything above = eager evaluations. Anything below = lazy evaluations.".Dump(); results.Dump(); 

样本输出

(在评估时,查询内部会打印出五个整数。正如您所看到的,只有一个计算通道)。

填充组实现输出