正确的LINQ语法,根据集合中的值对Ienumerable排序

本文关键字:Ienumerable 排序 集合 LINQ 语法 | 更新日期: 2023-09-27 17:52:48

我有以下类/表:

public class Shift
{
    public int ShiftID { get; set; }
    public DateTime ShiftDate { get; set; }
    public int DepartmentID { get; set; }
    //other irrelevant stuff...
    public virtual ICollection<ShiftMission> ShiftMission { get; set; }
}

public class ShiftMission
 {
    public int ShiftMissionID { get; set; }        
    public TimeSpan StartTime { get; set; }
    public int ShiftID { get; set; }
    //more irrelevant things
 }

在班次的索引视图中,我需要将列表按DepartmentID排序,然后按ShiftDate排序,最后按班次任务集合中最早/第一个任务的开始时间排序。真正让我困住的是分班任务。

我已经试过了,但是它告诉我没有列移位日期,也没有列departmentd:

    var allShifts = _context.Shifts
            .Include(s => s.Department)
            .Include(s => s.ShiftMission).ThenInclude(sm => sm.Activity)
            .OrderBy(s => s.DepartmentID)
            .ThenBy(s => s.ShiftDate)
            .ThenBy(s => s.ShiftMission.OrderBy(sm => sm.StartTime).Select(sm => sm).FirstOrDefault());
        return View(allShifts.ToList());

我还尝试将班次选择到一个新组中,但这让我感到困惑,并导致更多的异常,并将DepartmentA排序在DepartmentB下面

 var allShifts = _context.Shifts
            .Include(s => s.Department)
            .Include(s => s.ShiftMission).ThenInclude(sm => sm.Activity)
            .GroupBy(s => s.DepartmentID)
            .Select(group => new {Shifts = group.OrderBy(x => x.ShiftDate).ThenBy(x => x.ShiftMission.OrderBy(sm => sm.StartTime).First())})
            .SelectMany(group => group.Shifts);

实现这一点的正确方法是什么?我做的每一个变化都让我更加困惑。

正确的LINQ语法,根据集合中的值对Ienumerable排序

您希望按三个值对移位进行排序:

  1. DepartmentId,
  2. ShiftDate,
  3. Shift任务中所有StarTimes的最小StartTime。ShiftMissions

要在将在一个SQL查询中执行的一个查询中执行此操作,您可以加入DbSet _context。shift和_context。ShiftMissions on equal shiftId.

连接的结果可以按照您想要的方式排序:

var joinQuery = _context.Shifts.Join(_context.ShiftMissions, // join table Shifts and table ShiftMissions
    shift => shift.ShiftId,               // from the Shifts, take ShiftId
    shiftMission => shiftMission.ShiftId, // from the ShiftMisions taks ShiftId
    (shift, shiftMission) =>       // for all shifts and shiftMissions with equal shiftId take
    new {
        DepartmendId = shift.DepartmentId,
        ShiftDate = shift.ShiftDate,
        StartTime = shiftMission.StartTime,
        ShiftToSort = shift,
    });

注意,查询不会被执行。

如果您执行查询,您将看到您已经创建了一个表,其中包含包含DepartmentId, ShiftDate, StartTime和ShiftToSort的记录,其中包含原始的Shift,其中提取了要排序的三个属性。

现在,如果你把它们按正确的顺序排序,你会得到正确顺序的项目:

var orderedQuery = joinQuery
    .OrderBy(item => item..DepartmentId)
    .ThenBy(item => item.ShiftDate)
    .ThenBy(item => item.StartTime)

这个查询将导致太多的ShiftToSort:对于每个ShiftMission,匿名集合将有一个ShiftToSort

您只需要属性ShiftToSort的不同值

var shiftToSortQuery = orderedQuery
    .Select(item => item.ShiftToSort)
    .Distinct();

注意,查询仍然没有执行!

var orderedList = finalQuery.ToList();

当然你可以用一条语句来写:

var orderedList = _context.Shifts.Join(_context.ShiftMissions, // join table 
    ...
    .Distinct()
    .ToList();

如果您调查使用include时执行的SQL语句,您将看到include语句被转换为SQL连接。

var sortedQuery1 = _context.Shifts
    .OrderBy(shift => shift.DepartmentId)
    .ThenBy(shift => shift.ShiftDate);

结果必须按shift中所有ShiftMission项的最小StartTime排序)。因此,对于sortedQuery1中的每个元素,您需要计算ShiftMissions数组中的最小startTime。这是:

var sortedQuery2 = sortedQuery1
    .Orderby(itemSortedByDeparmentIdAndShiftDate =>
        // What value must be used to sort this item?
        // Answer: The minimum StartTime of all times in ShiftMissions
        // so for each item calculate the minimum Starttime:
        itemSortedByDepartmentIdAndShiftDate.ShiftMissions
            .Min(shiftMission => shiftMission.StartTime);

如果你使用你的数据库分析器,你会看到一个类似的连接和排序是完成的,也是完全在SQL中,因此非常有效

相关文章: