[英]Pivot table from sql to linq
我有以下两个表Events
和EventType
我需要做一些事情来显示我的列 EventType 名称(直接受益人、能力开发、Reach、Online Reach)和 Total 列,它是所有这些列的总和(特别是行):
*注意:如果Events表中没有eventTypeId,则pivot表中不显示该列。
这些数字代表 1 月、2 月等举行的所有活动的 TotalAttendants。
如果三月没有累积事件,则该月应该是空的(三月也会在这里,但不是数字,只是空格)。
我尝试遵循 linq 表达式:
var response = _context.Events
.Where(x => query.ProjectId.HasValue ? x.ProjectId.Equals(query.ProjectId) : true)
.Where(x => x.Date.Year.Equals(query.Year))
.Where(x => !x.IsDeleted)
.GroupBy(x => new { Year = x.Date.Year, Month = x.Date.Month })
.Select(x => new
{
DirectBeneficiaries = x.Where(m => m.EventTypeId == Domain.Enums.EventType.DirectBeneficiaries)
.Select(u => new EventTotal
{
Month = u.Date.Month.ToString("MMMM"),
FemaleAttendants = x.Sum(i => i.FemaleAttendants),
MaleAttendants = x.Sum(i => i.MaleAttendants),
TotalAttendants = x.Sum(i => i.TotalAttendants)
}),
CapacityDevelopment = x.Where(m => m.EventTypeId == Domain.Enums.EventType.CapacityDevelopment)
.Select(u => new EventTotal
{
Month = u.Date.Month.ToString("MMMM"),
FemaleAttendants = x.Sum(i => i.FemaleAttendants),
MaleAttendants = x.Sum(i => i.MaleAttendants),
TotalAttendants = x.Sum(i => i.TotalAttendants)
}),
Reach = x.Where(m => m.EventTypeId == Domain.Enums.EventType.Reach)
.Select(u => new EventTotal
{
Month = u.Date.Month.ToString("MMMM"),
FemaleAttendants = x.Sum(i => i.FemaleAttendants),
MaleAttendants = x.Sum(i => i.MaleAttendants),
TotalAttendants = x.Sum(i => i.TotalAttendants)
}),
OnlineReach = x.Where(m => m.EventTypeId == Domain.Enums.EventType.OnlineReach)
.Select(u => new EventTotal
{
Month = u.Date.Month.ToString("MMMM"),
FemaleAttendants = x.Sum(i => i.FemaleAttendants),
MaleAttendants = x.Sum(i => i.MaleAttendants),
TotalAttendants = x.Sum(i => i.TotalAttendants)
})
});
但我最后得到匿名类型,我不知道如何转换到我的EventTotal
model:
public class EventTotal
{
public string Month { get; set; }
public int? FemaleAttendants { get; set; }
public int? MaleAttendants { get; set; }
public int? TotalAttendants { get; set; }
}
我的问题是:如何将其转换为特定的 model?
更新#1:
我尝试使用此代码,但我有一个 db 异常。
"Column 'Events.TotalAttendants' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.\r\nThe multi-part identifier \"e.Date\" could not be bound.\r\nThe multi-part identifier \"e.Date\" could not be bound.\r\nThe multi-part identifier \"e.Date\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound.\r\nThe multi-part identifier \"e.EventTypeId\" could not be bound."
这是代码
var eligibleEvents = _context.Events
.Where(x => query.ProjectId.HasValue ? x.ProjectId.Equals(query.ProjectId) : true)
.Where(x => x.Date.Year.Equals(query.Year))
.Where(x => !x.IsDeleted)
.GroupBy(x => new { Year = x.Date.Year, Month = x.Date.Month, EventType = (int)x.EventTypeId });
var eventTotals = eligibleEvents.GroupBy(x => new { Year = x.Key.Year, Month = x.Key.Month },
(yearMonthCombination, eventsWithThisYearMonthCombination) => new EventTotal
{
Month = yearMonthCombination.Month,
CapacityDevelopment = eventsWithThisYearMonthCombination.Where(u => u.Key.EventType == (int)Domain.Enums.EventType.CapacityDevelopment).Select(u => u.Sum(s => s.TotalAttendants)).Sum(),
DirectBeneficiaries = eventsWithThisYearMonthCombination.Where(u => u.Key.EventType == (int)Domain.Enums.EventType.DirectBeneficiaries).Select(u => u.Sum(s => s.TotalAttendants)).Sum(),
OnlineReach = eventsWithThisYearMonthCombination.Where(u => u.Key.EventType == (int)Domain.Enums.EventType.OnlineReach).Select(u => u.Sum(s => s.TotalAttendants)).Sum(),
Reach = eventsWithThisYearMonthCombination.Where(u => u.Key.EventType == (int)Domain.Enums.EventType.Reach).Select(u => u.Sum(s => s.TotalAttendants)).Sum(),
Total = eventsWithThisYearMonthCombination.Select(u => u.Sum(s => s.TotalAttendants)).Sum(),
TotalAttendants = eventsWithThisYearMonthCombination.Select(u => u.Sum(s => s.TotalAttendants)).Sum()
}).ToList();
return eventTotals;
因此,从您的Events
序列中,您想要提取一系列EventTotals
:每组来自相同 [Year, Month] 的 EventTotal。
首先:我们可以优化查询的开始:将所有内容放在一个Where
:
var eligibleEvents = dbContext.Events
.Where(event => !event.IsDeleted
&& event.Date.Year == query.Year)
&& (!query.ProjectId.HasValue || query.ProjectId == event.ProjectId)
换句话说:从所有事件中,只保留那些尚未删除且Date.Year
等于query.Year
的事件。 根据query.ProjectId
是否为 null,您保留所有这些事件,或者仅保留ProjectId
的值等于query.ProjectId
的那些事件
考虑将 OR 简化如下:
(query.ProjectId == null) || (query.ProjectId == event.ProjectId)
现在从所有剩余的Events
中,我们制作事件组。 具有相同 [年、月] 组合的所有事件将在一个组中。 从每个组中,我们只制作一个EventTotal
。
如果你使用 GroupBy,并且你想从每个 Group 中创建一个 object,就像我们一样,考虑使用GroupBy 的重载,它有一个参数 resultSelector
继续 LINQ:
var eventTotals = eligibleEvents.GroupBy(event => new
{
Year = event.Date.Year,
Month = event.Date.Month,
},
// parameter resultSelector: from every [Year, Month] combination,
// and all eligible events that have these values of Year / Month,
// make one new EventTotal:
(yearMonthCombination, eventsWithThisYearMonthCombination) => new EventTotal
{
Month = yearMonthCombination.Month,
// Count the zero or more FemaleAttendants:
FemaleAttendants = eventsWithThisYearMonthCombination
.Select(event => event.FemaleAttendants)
.Sum(),
// Count the zero or more MaleAttendants:
MaleAttendants = eventsWithThisYearMonthCombination
.Select(event => event.MaleAttendants)
.Sum(),
TotalAttendants = eventsWithThisYearMonthCombination
.Select(event => event.TotalAttendants)
.Sum(),
}
如果TotalAttendants
始终是 FemaleAttendants 和 MaleAttendants 的总和,为什么它是一个单独的列? 考虑更改属性:
public int TotalAttendants => this.FemaleAttendants + this.MaleAttendants;
顺便问一下,为什么你的随从可以为空? 零服务员和null服务员有区别吗? 如果没有,请考虑删除可为空的,只会让您的生活更加困难。
如果你真的想要可以为空,那么零服务员什么时候应该转换为 null? 唉,你忘了定义这个。
您特别要求EventTotals
。 我不明白这将如何帮助您填写表格。
如果你想要一个带有 [Month, DirectBenificaries, CapacityDevelopment, ...] 的行,我会使用 go 换一个不同的 resultSelector:
(yearMonthCombination, eventsWithThisYearMonthCombination) => new
{
Month = yearMonthCombination.Month,
DirectBenificiaries = eventsWithThisYearMonthCombination
.Where(event => event.EventTypeId == dbContext.EventTypes
.Where(eventType => eventType.Name == "DirectBenificiaries")
.Select(event => ...)
.Sum(),
唉,您没有告诉我们您使用什么属性来构成 2020 年 1 月的 DirectBenificiaries。它是 DirectBenificiaries 类型的事件总数吗? 或者是 2020 年 1 月 DirectBenificiaries 的服务员总数?
其他列类似。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.