Я решил это с помощью комбинации метода ResolveUsing<T>()
и реализации IValueResolver
и метода ConvertUsing<T>()
и реализации ITypeConverter<TSource,TDestination>
.
Некоторые из моих сценариев отображения сложнее, чем обычно, включая двунаправленное отображение, вложенные классы и вложенные коллекции. Вышесказанное помогло мне их решить.
EDIT
По запросу я включил пример решения. Этот пример намного проще, чем реальные типы, с которыми я имел дело.
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
.