【问题标题】:Automapper: map many-to-manyAutomapper:映射多对多
【发布时间】:2020-01-29 16:46:44
【问题描述】:

我有以下型号:

public class Device
{
    public string DeviceId { get; set; }
    public string DeviceName { get; set; }

    private ICollection<TagDevice> _tagDevices;
    public virtual ICollection<TagDevice> TagDevices { get => _tagDevices ?? (_tagDevices = new List<TagDevice>()); protected set => _tagDevices = value; }

}

public class Tag : BaseEntity
{
    public string Name { get; set; }

    private ICollection<TagDevice> _tagDevices;
    public virtual ICollection<TagDevice> TagDevices { get => _tagDevices ?? (_tagDevices = new List<TagDevice>()); protected set => _tagDevices = value; }
}


public class TagDevice
{
    public int TagId { get; set; }
    public string DeviceId { get; set; }

    public virtual Tag Tag { get; set; }
    public virtual Device Device { get; set; }
}

我有 DTO 课程:

public class TagDisplayDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
    public int TimesUsed { get; set; }
    public int CarrierId { get; set; }
}

public class DeviceDisplayDto
{
    public string DeviceId { get; set; }
    public string DeviceName { get; set; }

    public List<TagDisplayDto> Tags { get; set; }    
}

现在,我想为 DeviceDisplayDto 创建带有标签的映射:

        CreateMap<Device, DeviceDisplayDto>()
            .ForMember(d => d.Tags, opt => opt.MapFrom(s => s.TagDevices...))
            ;

TagDevices 是集合而不是标签类型,集合的每个元素都有标签类型的属性。如何创建?

【问题讨论】:

    标签: entity-framework entity-framework-core many-to-many automapper


    【解决方案1】:

    您可以在TagDevices 的集合上使用Select() 将其转换为TagDisplayDtos 的列表:

    CreateMap<Device, DeviceDisplayDto>()
        .ForMember(deviceDisplayDto => deviceDisplayDto.Tags, options =>
            options.MapFrom(device => device.TagDevices.Select(tagDevice => new TagDisplayDto
            {
                CarrierId = 123,                // TODO
                CreatedAt = DateTime.UtcNow,    // TODO
                Id = tagDevice.TagId,
                Name = tagDevice.Tag.Name,
                TimesUsed = 0,                  // TODO
                UpdatedAt = DateTime.UtcNow,    // TODO
            }).ToList()));
    

    我将一些属性标记为 TODO,因为我不知道您正在使用的整个模型并且缺少一些属性。您需要自己填写。至少该代码应该可以帮助您入门。

    编辑#1

    正如 Lucian 所建议的,更好的解决方案是充分利用 AutoMapper 功能。在两个模型之间创建映射:

    • DeviceDeviceDisplayDto
    • TagDeviceTagDisplayDto
    CreateMap<Device, DeviceDisplayDto>()
        .ForMember(deviceDisplayDto => deviceDisplayDto.Tags, options =>
            options.MapFrom(device => device.TagDevices));
    CreateMap<TagDevice, TagDisplayDto>()
        .ForMember(tagDisplayDto => tagDisplayDto.CarrierId, options =>
            options.MapFrom(tagDevice => 123))                          // TODO
        .ForMember(tagDisplayDto => tagDisplayDto.CreatedAt, options =>
            options.MapFrom(tagDevice => DateTime.UtcNow.AddDays(-60))) // TODO
        .ForMember(tagDisplayDto => tagDisplayDto.Id, options =>
            options.MapFrom(tagDevice => tagDevice.TagId))
        .ForMember(tagDisplayDto => tagDisplayDto.Name, options =>
            options.MapFrom(tagDevice => tagDevice.Tag.Name))
        .ForMember(tagDisplayDto => tagDisplayDto.TimesUsed, options =>
            options.MapFrom(tagDevice => 0))                            // TODO
        .ForMember(tagDisplayDto => tagDisplayDto.UpdatedAt, options =>
            options.MapFrom(tagDevice => DateTime.UtcNow));             // TODO
    

    这样,上面定义的映射逻辑是可重用的。与我的第一个解决方案类似,您必须自己填写标有TODO 的属性。

    【讨论】:

    • 那是手册。您只需要 MapFrom 和地图而不是 Select。
    • @LucianBargaoanu,我更新了我的答案。随时添加更多反馈。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多