Automapper merging objects issue

2019-03-04 03:25发布

问题:

After getting automapper to work (previous question), I'm struggling with another problem (took it to another question, so the first one wouldn't be too complicated)...

I have next classes:

public class Model1
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDay { get; set; }
    public int Gender { get; set; }
    public string NickName { get; set; }
}    
public class Model2
{
    public bool Married { get; set; }    
    public int Children { get; set; }
    public bool HasPet { get; set; }
}

public class Entity1
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDay { get; set; }
    public int Gender { get; set; }
}    
public class Entity2
{
    public bool Married { get; set; }    
    public int Children { get; set; }
    public bool HasPet { get; set; }
    public string NickName { get; set; }
}

These objects are schematically similar to my original objects, except to the name and the complexity.

And AutoMapper configuration class (called from Global.asax):

public class AutoMapperConfig
{
    public static MapperConfiguration MapperConfiguration { get; set; }

    public static void Configure()
    {
        MapperConfiguration = new MapperConfiguration(cfg => {
            cfg.AddProfile<Out>();
            cfg.CreateMap<SuperModel, SuperEntity>();
        });
        MapperConfiguration.AssertConfigurationIsValid();
    }
}

public class Out: Profile
{
   protected override void Configure()
    {
        CreateMap<Model1, Entity1>();
        CreateMap<Model2, Entity2>()
            .ForMember(dest => dest.NickName, opt => opt.Ignore());
        CreateMap<Model1, Entity2>()
            .ForMember(dest => dest.Married, opt => opt.Ignore())
            .ForMember(dest => dest.Children, opt => opt.Ignore())
            .ForMember(dest => dest.HasPet, opt => opt.Ignore());
        CreateMap<SuperModel, SuperEntity>()
            .ForMember(dest => dest.Entity1, opt => opt.MapFrom(src => src.Model1))
            .ForMember(dest => dest.Entity2, opt => opt.MapFrom(src => src.Model2));
    }
}

When I need the object to be converted, I do next (at this point I have _superModel initialized and filled with data):

SuperEntity _superEntity = new SuperEntity();
AutoMapperConfig.MapperConfiguration.CreateMapper().Map<SuperModel, SuperEntity>(_superModel, _superEntity);

So, I map Model1 to Entity1 (witch is fine), and also Model2 to Entity2 (witch is also fine, except the Id property, which is ignored).

Main objects SuperModel and SuperEntity are mapped as well, and seems to work fine.

The problem happens, when I map Model1 to Entity2, to get the NickName (thought the rest of the properties are ignored). Some how It is always null!

Any ideas?

回答1:

The problem is you want to map a destination property (Entity2) from multiples source property values (Children, Married and HasPet from Model2 and Nickname from Model1).

You can solve your situation using an Custom Resolver or with AfterMap method.

Using Custom Resolvers:

You have to create a class inhering from ValueResolver to define how you will map Entity2 from an SuperModel:

public class CustomResolver : ValueResolver<SuperModel, Entity2>
{
    protected override Entity2 ResolveCore(SuperModel source)
    {
        return new Entity2
        {
            Children = source.Model2.Children,
            HasPet = source.Model2.HasPet,
            Married = source.Model2.Married,
            NickName = source.Model1.NickName
        };
    }
}

Then, use it like this:

CreateMap<SuperModel, SuperEntity>()
    .ForMember(dest => dest.Entity1, opt => opt.MapFrom(src => src.Model1))
    .ForMember(dest => dest.Entity2, opt => opt.ResolveUsing<CustomResolver>());

Using AfterMap:

You can execute actions after the mapping, so pass the value from Model1.Nickname to Entity2.Nickname after the map:

CreateMap<SuperModel, SuperEntity>()
    .ForMember(dest => dest.Entity1, opt => opt.MapFrom(src => src.Model1))
    .ForMember(dest => dest.Entity2, opt => opt.MapFrom(src => src.Model2))
            .AfterMap((m, e) => e.Entity2.NickName = m.Model1.NickName);