代码之家  ›  专栏  ›  技术社区  ›  Dimitris

如何使用automapper和constructUsing映射一个比较复杂的体系结构

  •  1
  • Dimitris  · 技术社区  · 7 年前

    我有以下情况,无法正确映射:

    我从对camunda api的调用中收到以下对象的列表。

    public class CamundaTask
    {
        public string FormKey { get; set; }
        public string Id { get; set; }
        public string Name { get; set; }
        ...
    }  
    

    我希望将其映射到代码中的特定任务( ContactUpdateTask OrganisationAquisitionTask )取决于formkey。

    以下是我的架构:

    public class BaseTask
    {
        public virtual string TaskType { get; set; }
        public string Id { get; set; }
        public int Priority { get; set; }
        public string Key { get; set; }
        ...
    }
    
    public abstract class ProcessTask<TContext> : BaseTask
    {
        public TContext TaskContext { get; set; }
    }
    
    public class ContactUpdateContext
    {
        public Guid PersonId { get; set; }
        public string FullName { get; set; }
    }
    
    public class OrganisationAquisitionContext
    {
        public Guid OrganisationId { get; set; }
        public string Name { get; set; }
    }
    
    public class ContactUpdateTask : ProcessTask<ContactUpdateContext>
    {
        public override string TaskType { get => "UpdateContact"; }
    }
    
    public class OrganisationAquisitionTask : ProcessTask<OrganisationAquisitionContext>
    {
        public override string TaskType { get => "OrganisationAquisition"; } 
    }
    

    我知道如何处理简单的继承和automapper,但整个TContext让我有点反感。 这就是我目前所知道的,但它会产生以下错误:“映射器未初始化。请使用适当的配置调用Initialize。”

    CreateMap<ContactUpdateTask, ProcessTask<ContactUpdateContext>>().ReverseMap();
    CreateMap<ContactValidationTask, ProcessTask<OrganisationAquisitionTask>>().ReverseMap();
    CreateMap<OrganisationAquisitionTask, ProcessTask<ContactValidationTask>>().ReverseMap();
    
    CreateMap<BaseTask, CamundaTask>()
       .ForMember(t => t.FormKey, opt => opt.MapFrom(p => p.TaskType))
       .ForMember(t => t.Assignee, opt => opt.MapFrom(p => p.Owner))
       .ForMember(t => t.Id, opt => opt.MapFrom(p => p.Key))
       .ForAllOtherMembers(opt => opt.Ignore());
    
    CreateMap<CamundaTask, ContactUpdateTask>()
        .ForMember(t => t.TaskType, opt => opt.MapFrom(p => p.FormKey))
        .ForMember(t => t.Owner, opt => opt.MapFrom(p => p.Assignee))
        .ForMember(t => t.Key, opt => opt.MapFrom(p => p.Id))
        .ForAllOtherMembers(opt => opt.Ignore());
    
    CreateMap<CamundaTask, ContactValidationTask>()
        .ForMember(t => t.TaskType, opt => opt.MapFrom(p => p.FormKey))
        .ForMember(t => t.Owner, opt => opt.MapFrom(p => p.Assignee))
        .ForMember(t => t.Key, opt => opt.MapFrom(p => p.Id))
        .ForAllOtherMembers(opt => opt.Ignore());
    
    CreateMap<CamundaTask, OrganisationAquisitionTask>()
        .ForMember(t => t.TaskType, opt => opt.MapFrom(p => p.FormKey))
        .ForMember(t => t.Owner, opt => opt.MapFrom(p => p.Assignee))
        .ForMember(t => t.Key, opt => opt.MapFrom(p => p.Id))
        .ForAllOtherMembers(opt => opt.Ignore());
    
    CreateMap<CamundaTask, BaseTask>()
        .ConstructUsing((CamundaTask task) =>
        {
            switch (task.FormKey.ToLower())
            {
                case "updateorganization":
                    return Mapper.Map<ContactUpdateTask>(task);
                case "contactValidation":
                    return Mapper.Map<ContactValidationTask>(task);
                case "organizationacquisition":
                    return Mapper.Map<OrganisationAquisitionTask>(task);       
            }
    
            return Mapper.Map<BaseTask>(task);
        })
       .ForMember(t => t.TaskType, opt => opt.MapFrom(p => p.FormKey))
       .ForMember(t => t.Owner, opt => opt.MapFrom(p => p.Assignee))
       .ForMember(t => t.Key, opt => opt.MapFrom(p => p.Id))
       .ForAllOtherMembers(opt => opt.Ignore());
    

    我使用以下代码行映射:

    var tasks = _mapper.Map<IEnumerable<BaseTask>>(camundaTasks)
    

    哪里 camundaTasks 属于类型 IEnumerable<CamundaTask>

    映射的正确方法是什么,以便我的任务列表包含 联系人更新任务 组织采购任务 取决于 CamundaTask ?

    1 回复  |  直到 7 年前
        1
  •  2
  •   nicolaas    7 年前

    因此,这里发生的事情是,您以非静态方式初始化Automapper(从您最初的帖子中不清楚,但我可以推断,因为我的评论似乎已经解决了您的问题),但您在ConstructUsing方法中静态地使用Automapper。

    有两种解决方案:

    1) 静态使用Automapper

    Mapper.Initialize(cfg=> cfg.CreateMap<CamundaTask, BaseTask>());
    

    2) 使用ResolutionContext

    .ConstructUsing((CamundaTask task, ResolutionContext context) =>
    {
        switch (task.FormKey.ToLower())
        {
            case "updateorganization":
                return context.Mapper.Map<ContactUpdateTask>(task);
            case "contactValidation":
                return context.Mapper.Map<ContactValidationTask>(task);
            case "organizationacquisition":
                return context.Mapper.Map<OrganisationAquisitionTask>(task);       
        }
    
        return context.Mapper.Map<BaseTask>(task);
    })