[英]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.