[英]LINQ group by date - include empty days WITHOUT using join
使用C#,NHibernate,NHibernate到LINQ。 使用NHibernate到LINQ,我沒有JOIN功能。 我也不能使用QueryOver。
我有一個LINQ查詢,它計算潛在客戶和銷售量。 該表僅在完成新的潛在客戶或銷售時創建,因此某些天沒有插入任何行。 執行以下查詢
var query3 = query2.AsEnumerable()
.Where(x => x.Created <= toDate.Value && 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個潛在顧客和銷售)。
如何包含這些日期,並允許它們不使用join設置LeadsCount = 0和SalesCount = 0而沒有?
編輯:
起作用的最終結果:
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 <= toDate.Value && 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<IGrouping<TKey, TElement>>
(從GroupBy
返回的類型)的擴展方法,有一種很棒的方法。 以我的拙見,出於多種原因,這是最好的方法:
.ToList()
也可以完成此操作,但要以急切的評估為代價), GroupBy
惰性評估(延遲執行), public static IEnumerable<IGrouping<TKey, TElement>> Fill<TKey, TElement>(this IEnumerable<IGrouping<TKey, TElement>> groups, IEnumerable<TKey> filling)
{
List<TKey> 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<TKey, TElement>(k);
}
class EmptyGrouping<TKey, TElement> : List<TElement>, IGrouping<TKey, TElement>
{
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();
(在對查詢進行評估時,從查詢內部打印出五個整數。您可以看到,只有一次計算通過)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.