Использование AutoMapper для снятия привязки DTO

Я пытаюсь использовать AutoMapper, чтобы сэкономить некоторое время от моих DTO до объектов моего домена, но у меня возникли проблемы с настройкой карты, чтобы она работала, и я начинаю задаваться вопросом, может ли AutoMapper быть неправильным инструментом для работа.

Рассмотрим этот пример объектов домена (один объект и одно значение):

public class Person { public string Name { get; set; } public StreetAddress Address { get; set; } } public class StreetAddress { public string Address { get; set; } public string City { get; set; } public string State { get; set; } } 

Мой DTO (от объекта Linq-to-SQL) выходит примерно так:

 public class PersonDTO { public string Name { get; set; } public string Address { get; set; } public string City { get; set; } public string State { get; set; } } 

Я хотел бы иметь возможность сделать это в моем репозитории:

 return Mapper.Map(result); 

Я попытался настроить AutoMapper так, как я могу себе представить, но я продолжаю получать общую конфигурацию карты Missing type или неподдерживаемую ошибку сопоставления , без каких-либо подробностей, чтобы сообщить мне, где я терпит неудачу.

Я пробовал несколько различных конфигураций, но вот несколько:

 Mapper.CreateMap() .ForMember(dest => dest.Address, opt => opt.MapFrom(Mapper.Map)); 

а также

 Mapper.CreateMap() .ForMember(dest => dest.Address.Address1, opt => opt.MapFrom(src => src.Address)) .ForMember(dest => dest.Address.City, opt => opt.MapFrom(src => src.City)) .ForMember(dest => dest.Address.State, opt => opt.MapFrom(src => src.State)); 

Я читал, что сглаживание объектов с помощью AutoMapper очень просто, но их непрозрачность непросто … или даже возможно. Может ли кто-нибудь сказать мне, пытаюсь ли я сделать невозможное, а если не то, что я делаю неправильно?

Обратите внимание, что мои фактические объекты немного сложнее, поэтому я могу оставить информацию, которая является ключом к ошибке … если то, что я делаю, выглядит правдой, я могу предоставить дополнительную информацию или начать упрощать свои объекты для тестирования ,

используйте https://github.com/omuleanu/ValueInjecter , он выполняет выравнивание и unflattening и что-то еще, что вам нужно, есть приложение примера asp.net mvc в загрузке, где демонстрируются все функции (также модульные тесты)

Это также работает для меня:

 Mapper.CreateMap(); Mapper.CreateMap() .ForMember(dest => dest.Address, opt => opt.MapFrom( src => src ))); 

В принципе, создайте сопоставление от dto для обоих объектов, а затем используйте его как источник для дочернего объекта.

Не могу опубликовать комментарий, поэтому отправляем ответ. Я предполагаю, что были некоторые изменения в реализации AutoMapper, поэтому ответ https://stackoverflow.com/a/5154321/2164198, предложенный HansoS, больше не компилируется. Хотя есть еще один метод, который можно использовать в таких сценариях – ResolveUsing :

 Mapper.CreateMap() .ForMember(dest => dest.Address, opt => opt.ResolveUsing( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; })) 

В дополнение к сиднейскому ответу и в соответствии с комментарием Тревора де Коккойка, возможно двустороннее сопоставление

 public class Person { public string Name { get; set; } public Address Address { get; set; } } public class Address { public string Street { get; set; } public string City { get; set; } public string State { get; set; } } public class PersonViewModel { public string Name { get; set; } public string AddressStreet { get; set; } public string AddressCity { get; set; } public string AddressState { get; set; } } 

Отображения Automapper

 Mapper.Initialize(cfg => cfg.RecognizePrefixes("Address")); Mapper.CreateMap(); Mapper.CreateMap(); Mapper.CreateMap() .ForMember(dest => dest.Address, opt => opt.MapFrom( src => src ))); 

Если вы реализуете class NameOf , вы можете избавиться от префикса magic string

 Mapper.Initialize(cfg => cfg.RecognizePrefixes(Nameof.Property(x => x.Address))); 

EDIT: В C # 6

 Mapper.Initialize(cfg => cfg.RecognizePrefixes(nameof(Person.Address))); 

Это может быть поздно, но вы можете решить это, используя lambda-выражения для создания объекта следующим образом:

 Mapper.CreateMap() .ForMember(dest => dest.Address, opt => opt.MapFrom( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; })) 

Я использую это

 public static void Unflatten(this IMemberConfigurationExpression opt) { var prefix = opt.DestinationMember.Name; var memberProps = typeof(TMember).GetProperties(); var props = typeof(TSource).GetProperties().Where(p => p.Name.StartsWith(prefix)) .Select(sourceProp => new { SourceProp = sourceProp, MemberProp = memberProps.FirstOrDefault(memberProp => prefix + memberProp.Name == sourceProp.Name) }) .Where(x => x.MemberProp != null); var parameter = Expression.Parameter(typeof(TSource)); var bindings = props.Select(prop => Expression.Bind(prop.MemberProp, Expression.Property(parameter, prop.SourceProp))); var resolver = Expression.Lambda>( Expression.MemberInit(Expression.New(typeof(TMember)), bindings), parameter); opt.ResolveUsing(resolver.Compile()); } 

конфигурация

 new MapperConfiguration(cfg => { cfg.CreateMap(); cfg.CreateMap().ForMember(x => x.HomeAddress, opt => opt.Unflatten()); }); 

модели

 public class Person { public string Name { get; set; } public Address HomeAddress { get; set; } } public class Address { public string Line1 { get; set; } public string Line2 { get; set; } public string City { get; set; } public string State { get; set; } public string ZipCode { get; set; } } 

Следуя соглашениям об уплотнении AutoMapper

 public class PersonDTO { public string Name { get; set; } public string HomeAddressLine1 { get; set; } public string HomeAddressLine2 { get; set; } public string HomeAddressCity { get; set; } public string HomeAddressState { get; set; } public string HomeAddressZipCode { get; set; } } 

Вероятно, требуется много улучшений, но он работает …

У меня есть другое решение. Основная идея заключается в том, что AutoMapper знает, как сгладить вложенные объекты при правильном присвоении свойств в сплющенном объекте: добавление имени свойства вложенного объекта в качестве префикса. Для вашего адреса Адрес является префиксом:

 public class PersonDTO { public string Name { get; set; } public string AddressCity { get; set; } public string AddressState { get; set; } ... } 

Поэтому создание знакомого сопоставления из вложенного в сплюснутое, а затем с использованием метода ReverseMap позволяет AutomMapper понять, как развязать вложенный объект .

 CreateMap() .ReverseMap(); 

Это все!

Interesting Posts

Как передать текущий элемент методу Java, нажав гиперссылку или кнопку на странице JSP?

Как избежать доступа к изменяемой переменной из закрытия

Что такое динамическая инициализация объекта в c ++?

dplyr :: mutate добавить несколько значений

Как интегрировать шаги Samsung Gear в приложении Android?

Чтение файла ресурсов изнутри банки

почему ngOnInit вызывается дважды?

Получение текущего рабочего каталога в Java

Gradle выдает ошибку «Не удалось создать плагин типа« AppPlugin »»

Что такое "Flash Flash Cache" и когда он должен использоваться?

Как отключить «автономный режим» gradleиента в студии Android?

Как программировать прокрутку Android WebView

Существуют ли различия в ожидании жизни для 1 ~ 2 ТБ внешнего (портативного) жесткого диска и внешнего (настольного) жесткого диска

Жесткий диск записывается, но не файловым менеджером

Как создать пользовательский валидатор в Play Framework 2.0?

Давайте будем гением компьютера.