我有以下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“。
如果我使用Dto
创建从SubEntity
到FromMember
的映射,那么Entity.Sub
将替换为SubEntity
的新实例,但这不是我想要的。我只是希望它在SubEntity
的{{1}}属性上更新现有Sub
实例的属性。
我如何实现这一目标?
答案 0 :(得分:20)
我通过结合使用ResolveUsing<T>()
方法并实施IValueResolver
和ConvertUsing<T>()
方法并实施ITypeConverter<TSource,TDestination>
来解决这个问题。
我的一些映射方案比普通方案更复杂,包括双向映射和嵌套类以及嵌套集合。以上帮助我解决了这些问题。
根据要求,我已经包含了一个示例解决方案。这个例子比我正在处理的实际类型简单得多。
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));
}
}
}
如果您运行使用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
的主要区别在于ResolveUsing
与MyResolver
一起使用以保留entity.Sub
的值。