如何使用AutoMapper将Dto映射到具有嵌套对象的现有对象实例?

我有以下Dto和实体与嵌套的子实体。

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; } } 

如何使用AutoMapper设置映射,这将允许我使用Dto中的值更新现有的Entity实例。

我正在使用Mapper.Map(dto, entity)更新现有实体但是当我尝试将Dto.SubProperty映射到Entity.Sub.SubProperty我得到一个例外, “必须解析为顶级成员。参数名称:lambdaExpression “

如果我使用FromMember创建从SubEntitySubEntity的映射,那么Entity.Sub将被替换为SubEntity的新实例,但这不是我想要的。 我只是想让它在EntitySub属性上更新现有SubEntity实例的属性。

我怎样才能做到这一点?

我通过结合使用ResolveUsing()方法并实现IValueResolverConvertUsing()方法并实现ITypeConverter

我的一些映射场景比正常情况更复杂,包括双向映射和嵌套类以及嵌套集合。 以上帮助我解决了这些问题。


编辑

根据要求,我已经包含了一个示例解决方案。 这个例子比我正在处理的实际类型简单得多。

 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() .ForMember(entity => entity.Sub, memberOptions => memberOptions.MapFrom(dto => dto)); Mapper.CreateMap(); } } 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() .ForMember(entity => entity.Sub, memberOptions => memberOptions.ResolveUsing()); Mapper.CreateMap(); } } 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)); } } } 

如果您运行使用MapperConfig的示例,您将获得以下输出:

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

字符串属性全部按照人们希望的那样更新,但是entity.Sub被替换为新的SubEntity实例,当你想要更新将持久存储到数据库的ORM的实体时,这个实例是没有用的。

如果您修改Main以便使用MapperConfig2 ,您仍然会像以前一样更新字符串属性, 但是entity.sub仍然具有与之前相同的SubEntity实例。 使用MapperConfig2运行示例提供此输出:

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

MapperConfig2的主要区别在于MapperConfig2MyResolver一起使用以保留MyResolver的值。