Search code examples
c#.netlinqselectmapper

How to use .Select() to map an object with list properties of different types in .NET


I am using .NET 7 and I have an Entity Framework Query that needs to be mapped to this DTO:

public record MachineScheduleDataDto
{
   public int MachineScheduleId { get; set; }
   public required ICollection<MachineOperationDto> MachineOperationsDto { get; set; }
}

My problem is that I don't know how to map the MachineOperationsDto propety, once it is an ICollection and have a type different of the class that will mapped it.

The EF query:

var test = _typedContext
    .AsNoTracking()
    .Include(m => m.MachineOperations!
        .Where(m =>
            m.InsertedAt.Date <= endDate.Date &&
            m.EndTime <= endDate.TimeOfDay &&
            m.InsertedAt.Date >= startDate.Date &&
            m.StartTime >= startDate.TimeOfDay))
    .ThenInclude(m => m.EggQuantities)
    .Where(m =>
        diffDays.Contains(m.WeekDay) &&
        m.MachineOperations!.Any() &&
        m.InitialProductionTime <= startDate.TimeOfDay &&
        m.FinalProductionTime >= startDate.TimeOfDay)
    .OrderBy(m => m.MachineScheduleId)
    .Select(m => new MachineScheduleDataDto
    {
        MachineScheduleId = m.MachineScheduleId,
        MachineOperationsDto = // Error because m.MachineOperation has the type "MachineOperation" and the MachineOperationsDto has the type "MachineOperationDto"
    });

The model that I'll use to make the map:

public class MachineOperation : BaseModel
{
    public int MachineOperationId { get; set; }
    public EMachineStatus MachineStatus { get; set; }
    public EDevStatus DevStatus { get; set; }
    public TimeSpan StartTime { get; set; }
    public TimeSpan EndTime { get; set; }

    #region Relationships

    public required virtual MachineSchedule MachineSchedule { get; set; }

    #endregion
}

The DTO:

public record MachineOperationDto
{
    public int MachineOperationId { get; set; }
    public EMachineStatus MachineStatus { get; set; }
    public virtual required MachineScheduleDataDto MachineScheduleDto { get; set; }
}

Solution

  • Project everything via Select

    var test = _typedContext
        .Where(m =>
            diffDays.Contains(m.WeekDay) &&
            m.MachineOperations!.Any() &&
            m.InitialProductionTime <= startDate.TimeOfDay &&
            m.FinalProductionTime >= startDate.TimeOfDay)
        .OrderBy(m => m.MachineScheduleId)
        .Select(m => new MachineScheduleDataDto
        {
            MachineScheduleId = m.MachineScheduleId,
            MachineOperationsDto = m.MachineOperations!
                .Where(mo =>
                    mo.InsertedAt.Date <= endDate.Date &&
                    mo.EndTime <= endDate.TimeOfDay &&
                    mo.InsertedAt.Date >= startDate.Date &&
                    mo.StartTime >= startDate.TimeOfDay)
                .Select(mo => new MachineOperationDto
                {
                    ... // other properties
                })
                .ToList()
        })
        .ToList();