Conditionally mapping one source type to two destination types

后端 未结 4 785
遇见更好的自我
遇见更好的自我 2020-12-20 01:15

I have a source DTO like this

public class Member 
{
    public string MemberId {get;set;}
    public string MemberType {get;set;}
    public string Name {g         


        
相关标签:
4条回答
  • 2020-12-20 01:34

    With automapper you must specify return type on invocation mapper eg. mapper.Map<PersonMember>(member), this tells that return type is PersonMember so you can't return CompanyMember.

    You can do something like this:

    var configPerson = new MapperConfiguration(cfg => cfg.CreateMap<Member, PersonMember>());
    var configCompany = new MapperConfiguration(cfg => cfg.CreateMap<Member, CompanyMember>());
    
    PersonMember personMember = null;
    CompanyMember companyMember = null;
    
    switch (member.MemberType )
    {
        case "PersonMember":
            var mapper = configPerson.CreateMapper();
            personMember = mapper.Map<PersonMember>(member);
            break;
        case "CompanyMember":
            var mapper = configCompany.CreateMapper();
            companyMember = mapper.Map<CompanyMember>(member);
            break;
        default:
            throw new Exception("Unknown type");
            break;
    }
    

    Or you can try Custom type converters with object as return type.

    0 讨论(0)
  • 2020-12-20 01:36

    Introduce some base class Member. Inherit PersonMember, CompanyMember from the new base class.

    Then define these mappings:

    cfg.CreateMap<Dto.Member, Member>()
        .ConstructUsing((memberDto, context) => {
        switch (memberDto.MemberType)
        {
            case "PersonMember":
                return context.Mapper.Map<PersonMember>(memberDto);
            case "CompanyMember":
                return context.Mapper.Map<CompanyMember>(memberDto);
            default:
                throw new ArgumentOutOfRangeException($"Unknown MemberType {memberDto.MemberType}");
        }
    });
    
    cfg.CreateMap<Dto.Member, PersonMember>()
        .ForMember(dest => PersonMember.PersonMemberId,
                   opt => opt.MapFrom(src => src.MemberId));
    
    cfg.CreateMap<Dto.Member, CompanyMember>()
        .ForMember(dest => CompanyMember.CompanyMemberId,
                   opt => opt.MapFrom(src => src.MemberId));
    

    Now you can map using _mapperInstance.Map<Member>(memberDto);

    0 讨论(0)
  • 2020-12-20 01:46

    I saw the example of conditionally mapping, but it maps the field it performs the conditional check on. I want to check the condition and map a different field.

    Try using such config:

    cfg.CreateMap<Member, PersonMember>()
        .ForMember(dest => PersonMember.PersonMemberId, opt => { 
            opt.Condition(src => src.MemberType == "Person");
            opt.MapFrom(src => src.MemberId);
         });
    cfg.CreateMap<Member, CompanyMember>()
        .ForMember(dest => CompanyMember.CompanyMemberId, opt => { 
            opt.Condition(src => src.MemberType == "Company");
            opt.MapFrom(src => src.MemberId);
         });
    

    In case you mapping from a non-compatible object Id field will be set to 0.

    0 讨论(0)
  • 2020-12-20 01:46

    For version 5 and above you could try below code:

    using System;
    using AutoMapper;
    
    namespace AutoMapOneToMulti
    {
        class Program
        {
            static void Main(string[] args)
            {
                RegisterMaps();
    
                var s = new Source { X = 1, Y = 2 };
    
                Console.WriteLine(s);
                Console.WriteLine(Mapper.Map<Source, Destination1>(s));
                Console.WriteLine(Mapper.Map<Source, Destination2>(s));
    
                Console.ReadLine();
            }
            static void RegisterMaps()
            {
                Mapper.Initialize(cfg => cfg.AddProfile<GeneralProfile>());
            }
        }
        public class GeneralProfile : Profile
        {
            public GeneralProfile()
            {
                CreateMap<Source, Destination1>();
                CreateMap<Source, Destination2>();
            }
        }
        public class Source
        {
            public int X { get; set; }
    
            public int Y { get; set; }
    
            public override string ToString()
            {
                return string.Format("Source = X : {0}, Y : {1}", X, Y);
            }
        }
        public class Destination1
        {
            public int X { get; set; }
    
            public int Y { get; set; }
            public override string ToString()
            {
                return string.Format("Destination1 = X : {0}, Y : {1}", X, Y);
            }
        }
        public class Destination2
        {
            public int X { get; set; }
    
            public int Y { get; set; }
            public override string ToString()
            {
                return string.Format("Destination2 = X : {0}, Y : {1}", X, Y);
            }
        }
    }
    

    And for version below 5 you could try this:

    using System;
    using AutoMapper;
    
    namespace AutoMapOneToMulti
    {
        class Program
        {
            static void Main(string[] args)
            {
                RegisterMaps();
    
                var s = new Source { X = 1, Y = 2 };
    
                Console.WriteLine(s);
                Console.WriteLine(Mapper.Map<Source, Destination1>(s));
                Console.WriteLine(Mapper.Map<Source, Destination2>(s));
    
                Console.ReadLine();
            }
            static void RegisterMaps()
            {
                Mapper.Initialize(cfg => cfg.AddProfile<GeneralProfile>());
            }
        }
        public class GeneralProfile : Profile
        {
            protected override void Configure()
            {
                CreateMap<Source, Destination1>();
                CreateMap<Source, Destination2>();
            }
        }
        public class Source
        {
            public int X { get; set; }
    
            public int Y { get; set; }
    
            public override string ToString()
            {
                return string.Format("Source = X : {0}, Y : {1}", X, Y);
            }
        }
        public class Destination1
        {
            public int X { get; set; }
    
            public int Y { get; set; }
            public override string ToString()
            {
                return string.Format("Destination1 = X : {0}, Y : {1}", X, Y);
            }
        }
        public class Destination2
        {
            public int X { get; set; }
    
            public int Y { get; set; }
            public override string ToString()
            {
                return string.Format("Destination2 = X : {0}, Y : {1}", X, Y);
            }
        }
    }
    

    If you want a dynamic function, use this extension:

    public static dynamic DaynamicMap(this Source source)
    {
        if (source.X == 1)
            return Mapper.Map<Destination1>(source);
        return Mapper.Map<Destination2>(source);
    }
    
    Console.WriteLine(new Source { X = 1, Y = 2 }.DaynamicMap());
    Console.WriteLine(new Source { X = 2, Y = 2 }.DaynamicMap());
    
    0 讨论(0)
提交回复
热议问题