假设我们从数据库中获得了这些值:
然后我必须为列表中缺少的第6个月和第8个月生成行,其中Total:0代表Id:1和Id:2
最终结果应该是:
如何使用LINQ和C#做到这一点? 如果我想到今年年底,就更难了。 g:第12个月,年份:2019年和第2个月,年份:2020年。
谢谢您的帮助!
答案 0 :(得分:1)
您想按(id和year)对记录进行分组,并在每组中找到边界(第一个月和上个月)以填补空白:
db.NAME_OF_THE_TABLE
.ToArray() // materialize the query, since this group by is unlikely to be supported by linq2...
.GroupBy(x => new { x.Id, x.Year }, (k, g) =>
{
var months = new { First = g.Min(x => x.Month), Last = g.Max(x => x.Month) };
// left join to fill the blank between the records
return (
from month in Enumerable.Range(months.First, months.Last - months.First + 1)
join row in g on month equals row.Month into match
from x in match.DefaultIfEmpty(new TYPE_OF_RECORD { Id = k.Id, Year = k.Year, Month = month, Total = 0 })
select x
);
})
.SelectMany(g => g) // flatten the grouping
答案 1 :(得分:0)
使用扩展方法来计算两个月之间的月数:
public static class DateTimeExt {
public static int MonthDiff(this DateTime d1, DateTime d2) => (d1.Year-d2.Year)*12+d1.Month-d2.Month;
}
您可以创建一个月份范围,然后填写缺少的月份。我使用Dictionary
查找一个月是否已经存在:
var ans = db.GroupBy(r => r.ID)
.AsEnumerable()
.SelectMany(rg => {
var rgd = rg.ToDictionary(r => (r.Month, r.Year));
var First = rg.Min(r => new DateTime(r.Year, r.Month, 1));
var Last = rg.Max(r => new DateTime(r.Year, r.Month, 1));
return Enumerable.Range(0, Last.MonthDiff(First) + 1).Select(moffset => {
var wd = First.AddMonths(moffset);
return rgd.TryGetValue((wd.Month, wd.Year), out var r) ? r : new { ID = rg.Key, wd.Month, wd.Year, Total = 0 };
});
});
AsEnumerable
应该将查询信息拉到本地,以便其余部分在LINQ to Objects中运行。
答案 2 :(得分:0)
您可以生成丢失的数据并创建联合。例如,
var list = new []
{
new Data{Month=5,Total=100,Year=2019,Id=1},
new Data{Month=7,Total=100,Year=2019,Id=1},
new Data{Month=5,Total=100,Year=2019,Id=2},
new Data{Month=9,Total=100,Year=2019,Id=2},
new Data{Month=2,Total=100,Year=2020,Id=2}
};
var result = list.GroupBy(x=>x.Id)
.Select(x=>
{
var minDate = x.ToList().Select(c=> new DateTime(c.Year,c.Month,1)).Min();
var maxDate = x.ToList().Select(c=> new DateTime(c.Year,c.Month,1)).Max();
return x.ToList().Union(Enumerable.Range(0, Int32.MaxValue)
.Select(e => minDate.AddMonths(e))
.TakeWhile(e => e <= maxDate)
.Select(e => new Data{Month=e.Month, Total=0,Year=e.Year,Id=x.Key}))
.OrderBy(v=> new DateTime(v.Year,v.Month,1))
.GroupBy(c=>new {c.Month,c.Year})
.Select(g=>g.First());
}).SelectMany(v=>v);
数据定义为
public class Data
{
public int Month{get;set;}
public int Year{get;set;}
public int Total{get;set;}
public int Id{get;set;}
}