如何使用 .Select() 在 .NET 中使用不同类型的列表属性映射对象

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

提问人:guirms 提问时间:11/9/2023 更新时间:11/9/2023 访问量:72

问:

我正在使用 .NET 7,并且我有一个需要映射到此 DTO 的实体框架查询:

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

我的问题是我不知道如何映射属性,一旦它是一个 ICollection 并且有一个不同的类类型来映射它。MachineOperationsDto

EF 查询:

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"
    });

我将用于制作地图的模型:

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; }
}

PS:我无法使用自动映射器,因为包含中的过滤器被自动映射器忽略,请参阅此处

C# .NET LINQ 选择 映射器

评论

2赞 Guru Stron 11/9/2023
MachineOperationsDto = new MachineOperationsDto { ... }但请注意,这将有相同的“问题”——它忽略了 的,您需要将过滤逻辑(从 include)移动到语句中。SelectIncludeSelect
2赞 Guru Stron 11/9/2023
另请注意 - 您可以使用 AutoMapper - 查看将过滤移动到映射器的建议(使用指向文档的链接更新了之前的答案 - docs.automapper.org/en/latest/...)
1赞 Guru Stron 11/9/2023
* MachineOperationsDto = m.MachineOperation.Where(...).Select(x => new MachineOperationsDto { ... })
0赞 Svyatoslav Danyliv 11/9/2023
您可以使用 Automapper,但不能使用 method。具体化查询,然后应用 Automapper。ProjectTo
1赞 Guru Stron 11/10/2023
@quirms在 AutoMapper 中设置过滤不会导致“过早”具体化。

答:

1赞 Svyatoslav Danyliv 11/9/2023 #1

通过以下方式投影所有内容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();

评论

0赞 Lucian Bargaoanu 11/9/2023
docs.automapper.org/en/latest/......
0赞 Svyatoslav Danyliv 11/9/2023
@LucianBargaoanu,如果此查询不使用 AutoMapper,此链接应该告诉我什么?这是常规的 Eager Loading 查询。
0赞 Lucian Bargaoanu 11/9/2023
它说你怎么做,你说你不能使用它:)ProjectTo
0赞 Svyatoslav Danyliv 11/9/2023
@LucianBargaoanu,您可以根据参数使用过滤器吗?这是无用的情况。ProjectToProjectTo
0赞 Lucian Bargaoanu 11/9/2023
docs.automapper.org/en/latest/......