GroupBy()未在List <t>属性上正确分组

时间:2018-06-13 16:38:16

标签: c# asp.net-mvc linq .net-core

我正在试图显示一个“周列表”(一周中的每一天),要么显示所有5天(周一至周五),要么显示单个“列表项”(重复列出一周中所有日期的单个列表项)如果所有项目每天都相同(除了密钥)。以下内容有效,直到我将“DayFunctions”(列表)添加为“周列表”的项目。使用List属性进行分组时是否需要执行某些不同的操作?

我无法找到解决此特定分组问题的任何内容,甚至谷歌搜索(几天)。

使用自定义比较器更新

//POCO
public class ScheduleWeek : IScheduleWeek
{
    public int Id { get; set; }
    public int Yr { get; set; }
    public int WeekNo { get; set; }
    public List<ScheduleDay> ScheduleDays { get; set; }
}


// POCO
public class ScheduleDay : IScheduleDay
{
    public int Id { get; set; }
    public int ScheduleWeekId { get; set; }
    public string EmpId { get; set; }
    public DateTime ScheduleDayDt { get; set; }
    public Shift Shift { get; set; }
    public Station Station { get; set; }
    public List<DayFunction> DayFunctions { get; set; }
}

// POCO
public class DayFunction
{
    public int ScheduleDayId { get; set; }
    public int FunctionId { get; set; }
}


// HELPER METHOD
public async Task<List<ScheduleDay>> GetScheduleDaysWithDayFunctions(int stationId, 
                                                                        string empId, 
                                                                        int scheduleWeekId)
{
    var sdlist = await _ctx.ScheduleDays
        .Where(sd => sd.ScheduleDayDt.DayOfWeek != DayOfWeek.Sunday &&
                        sd.ScheduleDayDt.DayOfWeek != DayOfWeek.Saturday &&
                        sd.Station.Id == stationId &&
                        sd.EmpId == empId &&
                        sd.ScheduleWeekId == scheduleWeekId)
        .Include(d => d.DayFunctions)
        .ToListAsync();

    return sdlist;
}

// HELPER METHOD
//  ** ADDED CUSTOM COMPARER
public class ScheduleDayComparer : IEqualityComparer<ScheduleDay>
{
    public bool Equals(ScheduleDay x, ScheduleDay y)
    {
        return x.Id == y.Id && x.DayFunctions
                    .SequenceEqual(y.DayFunctions);
    }

    public int GetHashCode(ScheduleDay x)
    {
        return x.Id.GetHashCode() ^ x.DayFunctions
                    .Aggregate(0, (a, y) => a ^ y.GetHashCode());
    }
}

// MODEL FOR VIEW
public class ScheduleWeekViewModel
{
    public ScheduleWeek ScheduleWeek { get; set; }
    public ScheduleHelpers ScheduleHelpers { get; set; }
}


// MVC VIEW
@{
    var scheduleDayComparer = new ScheduleHelpers.ScheduleDayComparer(); // <-- ADDED        
    var scheduledays = Model.ScheduleHelpers
        .GetScheduleDaysWithDayFunctions(station.Id,
            employee.Id.ToString(),
            Model.ScheduleWeek.Id).Result
        .GroupBy(x => x, scheduleDayComparer) // <-- ADDED
            .Select(g => g.First())           // <-- ADDED
            .ToList();                        // <-- ADDED
        //.GroupBy(sd => new
        //    {
        //        sd.Shift.Id,
        //        sd.DayFunctions // <-- this causes the grouping to break
        //    })
        //.Select(g => g.First());
}
<table>
    @foreach (var scheduleday in scheduledays)
    {
        <tr>
            <td>
                <text>SHIFT: @scheduleday.Shift.Name </text>
            </td>
            <td>
                @foreach (var df in scheduleday.DayFunctions)
                    {
                        <text>DAY FUNCTIONS: @df.FunctionId </text>
                    }   
            </td>
        </tr>
    }
</table>

//  CONTROLLER ACTION
public async Task<IActionResult> LocationScheduler()
{
    var vm = new ScheduleWeekViewModel{};
    var user = await _userManager.GetUserAsync(User);
    vm.Employees = await _tcomsHelpers.GetEmployeesOfSupervisor(user);
    vm.ScheduleDays = await _scheduleHelpers.GetScheduleWeekDaysForScheduler(vm.Employees);
    vm.ScheduleWeek = await _scheduleHelpers.GetCurrentScheduleWeek();
    vm.ScheduleHelpers = _scheduleHelpers;
    return View(vm);
}

1 个答案:

答案 0 :(得分:0)

当您在GroupBy中包含列表属性时,最终会在GroupBy实施内部进行列表比较,这通常不是您想要的。

您可以解决此问题by implementing a custom IEqualityComparer,但是您必须为组密钥定义命名类型,因为无法为匿名类型定义IEqualityComparer。另一种方法是按复合string键进行分组,如下所示:

.GroupBy(sd => new {
    sd.Shift.Id
,   string.Join(
        "|"
    ,   sd.DayFunctions
            .OrderBy(f => f.ScheduleDayId).ThenBy(f => f.FunctionId)
            .Select(f => $"{f.ScheduleDayId}:{f.FunctionId}")
    )
})