繁体   English   中英

Pivot 表从 sql 到 linq

[英]Pivot table from sql to linq

我有以下两个表EventsEventType

我需要做一些事情来显示我的列 EventType 名称(直接受益人、能力开发、Reach、Online Reach)和 Total 列,它是所有这些列的总和(特别是行):

结果

我的 sql 表是结构化的,就像在这张图片上一样: SQL 表

*注意:如果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。

  • 好吧,不是所有事件,只有那些没有被删除的事件
  • 而那些没有被删除的,你只想要那些与 ProjectId 和 Year 匹配的

首先:我们可以优化查询的开始:将所有内容放在一个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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM