c# - Automapper引用自定义成员映射中现有的子类型映射

标签 c# automapper

我的数据库实体如下所示(已编辑为相关信息):

public class Task
{
    public Guid? StatusId { get; set; }
    public Status Status { get; set; }

    public DateTime? StatusLastModified { get; set; }
}

public class Status
{
    public string Name { get; set; }
    // several other properties redacted
}

任务最初没有状态(StatusLastModified 也为空),一旦分配了第一个状态,任务将始终具有状态(并且 StatusLastModified 也不再为空)。

对于这个问题,您可以假设这些属性始终为 null 或非 null,我不需要考虑一个为 null 而另一个不为 null 的异常情况。

对于我的 DTO,我想将其映射到以下结构:

public struct TaskDto
{
    public TaskStatusDto? Status { get; set; }
}

public struct TaskStatusDto
{
    public DateTime Timestamp { get; set; } // maps from Task.StatusLastModified 
    public StatusDto Status { get; set; } // maps from Task.Status
}

public struct StatusDto
{
    public string Name { get; set; }
    // and all the other properties from the Status entity
}

这里的目标是,当存在实际状态时,我的 TaskDto 仅具有底层 TaskStatusDto,否则它应该为 null。这很有用,因为它不需要不断地对状态对象和最后修改日期进行空检查。

但是,我很难在 Automapper 中配置此映射。我已经创建了 StatusStatusDto 之间的映射:

configuration
     .CreateMap<Status, StatusDto>();

我的真实映射更复杂,但它也被证明是有效的,因此您可以假设这是一个有效且有效的映射。

我面临的问题是在 TaskTaskDto 之间创建自定义映射时如何引用此映射。我目前已尝试以下操作:

configuration
    .CreateMap<Task, TaskDto>()
    .ForMember(
            dto => dto.Status,
            opt => opt.MapFrom(entity => 
                entity.Status == null
                    ? null as TaskStatusDto?
                    : new TaskStatusDto()
                    {
                        TimeStamp = entity.StatusLastModified.Value,
                        Status = // ??? make me a StatusDto from entity.Status
                    }
        ));

我不知道怎么填写的部分是评论。我可以访问原始实体 (entity.Status),但我不知道如何告诉 Automapper 根据它的映射将此对象转换为 StatusDto应该已经知道了。

我的方法也感觉比应有的更人为,但如果我的源数据中没有实际实体支持,我不知道如何引入这个中间 TaskStatusDto 对象。

<小时/>

一个小脚注,不确定是否相关:我正在使用 Heroic.Automapper ,这意味着 TaskDtoStatusDto 映射被配置在不同的位置(即在 TaskDtoStatusDto 内部)类),Heroic 框架将在运行时组合所有这些 map 。

public class TaskDto : IMapFrom<Task>, IHaveCustomMappings
{
     public void CreateMappings(IMapperConfigurationExpression configuration)
     {
         // mapping from Task to TaskDto
     }
}

public class StatusDto : IMapFrom<Status>, IHaveCustomMappings
{
     public void CreateMappings(IMapperConfigurationExpression configuration)
     {
         // mapping from Status to StatusDto
     }
}

但是,据我了解, map 本身的设置并不是英雄特定的,应该是纯粹的 Automapper 语法。

最佳答案

我认为更干净的解决方案是创建您自己的 CustomResolver :

public class TaskStatusDtoResolver : IValueResolver<Task, TaskDto, TaskStatusDto?>
{
    public TaskStatusDto? Resolve(Task source, TaskDto destination, TaskStatusDto? member, ResolutionContext context)
    {
        if (source.Status == null)
        {
            return null;
        }

        return new TaskStatusDto
        {
            Status = context.Mapper.Map<StatusDto>(source.Status),
            Timestamp = source.StatusLastModified.Value
        };
    }
}

您可以使用以下配置:

cfg.CreateMap<Status, StatusDto>();
cfg.CreateMap<Task, TaskDto>()
    .ForMember(dest => dest.Status, opt => opt.MapFrom<TaskStatusDtoResolver>());

See the working example here

<小时/>

或者,您可以在配置中定义所有映射:

var configuration = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Status, StatusDto>();
    cfg.CreateMap<Task, TaskDto>().ForMember(
         dest => dest.Status,
         src => src.MapFrom((task, taskDto, member, context) =>
         {
             return task.Status == null ? null as TaskStatusDto? : new TaskStatusDto()
             {
                 Timestamp = task.StatusLastModified.Value,
                 Status = context.Mapper.Map<StatusDto>(task.Status)
             };
         }
     ));
});

关于c# - Automapper引用自定义成员映射中现有的子类型映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60225687/

相关文章:

c# - 在 C# 中执行参数化查询时出现 ORA-01745 错误

c# - 如何将 Microsoft.CodeAnalysis.ITypeSymbol 与 System.Type 进行比较

c# - 棋盘游戏棋子移动算法

c# - 在多人游戏中处理多个按键

c# - Linq to Entities 选择具有最大日期的数据?

asp.net-mvc - 如何将 EditModel 映射到命令消息?

c# - 转换为值类型失败,因为物化值为 null

c# - 如何修复 Automapper 将连接表映射到 ViewModel

entity-framework - 使用 Automapper 实现多对多到 DTO

c# - Automapper - RecognizePrefixes 不起作用