How do you map a Dto to an existing object instance with nested objects using AutoMapper?

后端 未结 1 1686
遇见更好的自我
遇见更好的自我 2020-12-03 03:42

I have the following Dto and entity with a nested sub entity.

public class Dto
{
    public string Property { get; set; }
    public string SubProperty { get         


        
相关标签:
1条回答
  • 2020-12-03 04:30

    I solved it by using a combination of the ResolveUsing<T>() method and implementing IValueResolver and the ConvertUsing<T>() method and implementing ITypeConverter<TSource,TDestination>.

    Some of my mapping scenarios are more complicated than normal including bidirectional mapping and nested classes and nested collections. The above helped me to solve them.


    EDIT

    As requested, I've included an example solution. This example is much simpler than the actual types I was dealing with.

    using System;
    using AutoMapper;
    
    namespace TestAutoMapperComplex
    {
        public class Dto
        {
            public string Property { get; set; }
            public string SubProperty { get; set; }
        }
    
        public class Entity
        {
            public string Property { get; set; }
            public SubEntity Sub { get; set; }
        }
    
        public class SubEntity
        {
            public string SubProperty { get; set; }
        }
    
        static class MapperConfig
        {
            public static void Initialize()
            {
                Mapper.CreateMap<Dto, Entity>()
                    .ForMember(entity => entity.Sub, memberOptions =>
                        memberOptions.MapFrom(dto => dto));
                Mapper.CreateMap<Dto, SubEntity>();
            }
        }
    
        static class MapperConfig2
        {
            private class MyResolver : IValueResolver
            {
    
                public ResolutionResult Resolve(ResolutionResult source)
                {
                    var destinationSubEntity = ((Entity)source.Context.DestinationValue).Sub;
    
                    Mapper.Map((Dto)source.Value, destinationSubEntity);
    
                    return source.New(destinationSubEntity, typeof(SubEntity));
                }
            }
    
            public static void Initialize()
            {
                Mapper.CreateMap<Dto, Entity>()
                    .ForMember(entity => entity.Sub, memberOptions =>
                        memberOptions.ResolveUsing<MyResolver>());
                Mapper.CreateMap<Dto, SubEntity>();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                MapperConfig.Initialize();
    
                var dto = new Dto {Property = "Hello", SubProperty = "World"};
                var subEntity = new SubEntity {SubProperty = "Universe"};
                var entity = new Entity {Property = "Good bye", Sub = subEntity};
    
                Mapper.Map(dto, entity);
    
                Console.WriteLine(string.Format("entity.Property == {0}, entity.Sub.SubProperty == {1}",
                    entity.Property, entity.Sub.SubProperty));
                Console.WriteLine(string.Format("entity.Sub == subEntity: {0}", 
                    entity.Sub == subEntity));
    
            }
        }
    }
    

    If you run the example, which is using MapperConfig, you'll get the following output:

    entity.Property == Hello, entity.Sub.SubProperty == World
    entity.Sub == subEntity: False
    

    The string properties all get updated as one would want them to, but entity.Sub gets replaced with a new instance of SubEntity which is no good for when you are wanting to update entities for an ORM that will be persisted to a database.

    If you modify Main so that MapperConfig2 is used instead, you'll still have the string properties updated as before, but, entity.sub still has the same instance of SubEntity that it had before. Running the example with MapperConfig2 gives this output:

    entity.Property == Hello, entity.Sub.SubProperty == World
    entity.Sub == subEntity: True
    

    The key difference in MapperConfig2 is that ResolveUsing is used along with MyResolver to preserve the value of entity.Sub.

    0 讨论(0)
提交回复
热议问题