LINQ - 以月为单位拆分结果
LINQ - Split results in months
我正在使用 Entity Framework,并且我有以下 classes:
public sealed class Class
{
[Key]
public int Id { get; init; }
public IEnumerable<Student> Students { get; init; } = null!;
}
public sealed class Student
{
[Key]
public int Id { get; init; }
public IEnumerable<Point> Points { get; init; } = null!;
public sealed class Point
{
[Key]
public int Id { get; init; }
public DateTime DateTime { get; set; }
public int MathPoints { get; set; }
public int LanguagePoints { get; set; }
现在,我需要编写一个查询,它选择一个 class,但是对于那个 class,创建一个包含 12 个元素的集合(每个月一个),其中每个集合包含一组有限的人(例如 2),以及他们的分数。
输出类似于:
[
{
"date": "2022/01/01",
"totalPoints": 195, // This is the sum of ALL points of ALL students in this month.
"students": [
{
"name": "student 1",
"points": 100 // This is a sum of the `MathPoints` and the `LanguagePoints`.
},
{
"name": "student 2",
"points": 75 // This is a sum of the `MathPoints` and the `LanguagePoints`.
},
{
"name": "others",
"points": 20 // This is a sum of the `MathPoints` and the `LanguagePoints`.
}
]
},
// .. Repeated here for all the other months in the year.
]
我知道这可以通过执行一些 linq 查询来实现,但我希望它尽可能优化。
谁能提供一些有关如何解决此问题的信息?
编辑:
应返回一个IEnumerable
,其中包含以下字段:
public sealed class Report
{
public DateTime Date { get; set; }
public int TotalPoints { get; set; }
public IEnumerable<StudentReport> StudentReports { get; set; }
}
public sealed class StudentReport
{
public string Name { get; set; }
public int Points { get; set; }
}
您必须将此类查询分成两部分 - 加载最少的所需数据并在客户端分组。需要在客户端分组,因为您的结果包含分组的详细信息。
// input parameters
var classId = ...;
var year = 2022;
// parameters for range filter
var startDate = new DateTime(year, 1, 1);
var endDate = startDate.AddYear(1);
var query =
from c in context.Class
from s in c.Students
from p in s.Points
where c.Id == classId &&
p.DateTime >= startDate && p.DateTime < endDate
group p by new { p.DateTime.Year, p.DateTime.Month, s.Id, s.Name } into g
select new
{
Year = g.Key.Year,
Month = g.Key.Month,
Points = g.Sum(x => x.MathPoints + x.LanguagePoints),
Name = g.Key.Name
};
// materialize items, grouping should be provided on the client side
var rawItems = await query.ToListAsync();
var resultQuery =
from r in rawItems
group r by new { r.Year, r.Month } into g
select new Report
{
Date = new DateTime(g.Key.Year, g.Key.Month, 1),
TotalPoints = g.Sum(x => x.Points),
StudentReports = g.Select(x => new StudentReport
{
Name = x.Name,
Points = x.Points
})
.ToList()
}
var result = resultQuery.ToList();
我正在使用 Entity Framework,并且我有以下 classes:
public sealed class Class
{
[Key]
public int Id { get; init; }
public IEnumerable<Student> Students { get; init; } = null!;
}
public sealed class Student
{
[Key]
public int Id { get; init; }
public IEnumerable<Point> Points { get; init; } = null!;
public sealed class Point
{
[Key]
public int Id { get; init; }
public DateTime DateTime { get; set; }
public int MathPoints { get; set; }
public int LanguagePoints { get; set; }
现在,我需要编写一个查询,它选择一个 class,但是对于那个 class,创建一个包含 12 个元素的集合(每个月一个),其中每个集合包含一组有限的人(例如 2),以及他们的分数。
输出类似于:
[
{
"date": "2022/01/01",
"totalPoints": 195, // This is the sum of ALL points of ALL students in this month.
"students": [
{
"name": "student 1",
"points": 100 // This is a sum of the `MathPoints` and the `LanguagePoints`.
},
{
"name": "student 2",
"points": 75 // This is a sum of the `MathPoints` and the `LanguagePoints`.
},
{
"name": "others",
"points": 20 // This is a sum of the `MathPoints` and the `LanguagePoints`.
}
]
},
// .. Repeated here for all the other months in the year.
]
我知道这可以通过执行一些 linq 查询来实现,但我希望它尽可能优化。
谁能提供一些有关如何解决此问题的信息?
编辑:
应返回一个IEnumerable
,其中包含以下字段:
public sealed class Report
{
public DateTime Date { get; set; }
public int TotalPoints { get; set; }
public IEnumerable<StudentReport> StudentReports { get; set; }
}
public sealed class StudentReport
{
public string Name { get; set; }
public int Points { get; set; }
}
您必须将此类查询分成两部分 - 加载最少的所需数据并在客户端分组。需要在客户端分组,因为您的结果包含分组的详细信息。
// input parameters
var classId = ...;
var year = 2022;
// parameters for range filter
var startDate = new DateTime(year, 1, 1);
var endDate = startDate.AddYear(1);
var query =
from c in context.Class
from s in c.Students
from p in s.Points
where c.Id == classId &&
p.DateTime >= startDate && p.DateTime < endDate
group p by new { p.DateTime.Year, p.DateTime.Month, s.Id, s.Name } into g
select new
{
Year = g.Key.Year,
Month = g.Key.Month,
Points = g.Sum(x => x.MathPoints + x.LanguagePoints),
Name = g.Key.Name
};
// materialize items, grouping should be provided on the client side
var rawItems = await query.ToListAsync();
var resultQuery =
from r in rawItems
group r by new { r.Year, r.Month } into g
select new Report
{
Date = new DateTime(g.Key.Year, g.Key.Month, 1),
TotalPoints = g.Sum(x => x.Points),
StudentReports = g.Select(x => new StudentReport
{
Name = x.Name,
Points = x.Points
})
.ToList()
}
var result = resultQuery.ToList();