Атрибут Automapper MapsTo не работает со ссылочными классами

Я изо всех сил пытаюсь понять, что я здесь делаю не так. Я использовал Automapper + Automapper.Attributes (https://github.com/schneidenbach/AutoMapper.Attributes) в решении, и недавно мне пришлось разделить мой проект API на «базовую» библиотеку и исходный API. Automapper не может создать карту, когда файлы классов перемещаются за пределы проекта API. Я установил демонстрационный проект со следующей структурой, чтобы подтвердить эту проблему: (Доступно здесь: https://github.com/greghesom/AutoMapper_Example)

  • Решение
    • API (класс клиента и человека)
    • API.Core (классы Pet и Dog)

  • Проект API ссылается на API.Core
  • Класс Pet соответствует классу Dog
  • Класс Person сопоставляется с классом Customer

API.Core - Класс собаки

namespace API.Core
{
    public class Dog
    {
        public string Name { get; set; }
    }
}

API.Core - класс домашних животных

namespace API.Core
{
    [MapsTo(typeof(Dog))]
    public class Pet
    {
        [MapsToProperty(typeof(Dog), "Name")] //Edit: Fixed this typo
        public string PetName { get; set; }
    }
}

API - класс человека

namespace API.Models
{
    [MapsTo(typeof(Customer))]
    public class Person
    {
        [MapsToProperty(typeof(Customer), "FirstName")]
        public string Name { get; set; }
    }
}

API - Класс клиента

namespace API.Models
{
    public class Customer
    {
        public string FirstName { get; set; }
    }
}

API - Запуск

   AutoMapper.Mapper.Initialize(cfg => {
                typeof(API.WebApiConfig).Assembly.MapTypes(cfg);  
            });

API - Контроллер

var person = new Person { Name = "John" };
var customer = AutoMapper.Mapper.Map<Customer>(person);//This Works

var dog = new Dog { Name = "Lucky" };
var pet = AutoMapper.Mapper.Map<Pet>(dog);//This throws exception

ИСКЛЮЧЕНИЕ:

An error has occurred. Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters ============================= AutoMapper created this type map for you, but your types cannot be mapped using the current configuration. Dog -> Pet (Destination member list) API.Core.Dog -> API.Core.Pet (Destination member list)

Unmapped properties: PetName AutoMapper.AutoMapperConfigurationException at lambda_method(Closure , Dog , Pet , ResolutionContext ) at lambda_method(Closure , Object , Object , ResolutionContext ) at API.Controllers.ValuesController.Get() in c:\users\greg\Source\Repos\AutoMapperTest\API\Controllers\ValuesController.cs:line 26 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()

MapsToProperty в классе PetName класса Pet объявлен неправильно. Это должно быть typeof (Собака) вместо typeof (Pet).

user1672994 07.06.2018 16:15

В проекте GITHub есть тестовые примеры с этим конкретным методом, я предлагаю сравнить и запустить эти тесты и проверить эти образцы и ваш код.

Cleptus 07.06.2018 16:16

@ user1672994 добавьте его в качестве ответа ;-)

Cleptus 07.06.2018 16:17

Приносим извинения за опечатку в MapsToProperty. Я обновил пример проекта, но проблема все еще существует

Greg 07.06.2018 16:20

Подходит ли вам отображение var customer = new Customer{ Name = "John" }; var person = AutoMapper.Mapper.Map<Person>(customer);? Поскольку вы определили карту для сопоставления человека и курса, в вашем вопросе это сработало. Но в случае Dog вы определили сопоставление для Pet с Dog, но вы пытаетесь сопоставить объект dog с объектом pet (а сопоставление не существует).

user1672994 07.06.2018 18:53

Вы когда-нибудь находили решение этого? Я наткнулся на эта статья и попробовал, и это, похоже, сработало, но простое использование services.AddAutoMapper() не помогло, не уверен, является ли то, что предлагается в статье, правильным подходом или нет.

akousmata 22.10.2018 20:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
6
4 281
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

MapsToProperty в классе PetName класса Pet объявлен неправильно. Это должно быть typeof (Собака) вместо typeof (Pet).

    [MapsTo(typeof(Dog))]
    public class Pet
    {
        [MapsToProperty(typeof(Dog), "Name")]
        public string PetName { get; set; }
    }

Редактировать

Поскольку вы определили сопоставление для сопоставления Person с Customer, в вашем вопросе это сработало. Но в случае Dog вы определили сопоставление для Pet с Dog, но вы пытаетесь сопоставить объект dog с объектом pet (но сопоставление не существует).

Если вам требуется двухстороннее сопоставление, вам будет предложено определить сопоставление с помощью MapsToAndFromProperty.

Проверьте ссылку это для получения дополнительной информации.

Это была опечатка, я исправил ее, но проблема все еще существует.

Greg 07.06.2018 16:22
Ответ принят как подходящий

Я столкнулся с той же проблемой (AutoMapper 7.0.0). Ключ к проблеме находится в сообщении об ошибке: «AutoMapper создал эту карту типов для вас, но ваши типы не могут быть сопоставлены с использованием текущей конфигурации». Начиная с версии 6.2.0, AutoMapper пытается сам создавать сопоставления для типов, которые не отображаются явно, то есть: во многих случаях создание сопоставления больше не требуется.

Однако кажется, что он использует сопоставления, которые он создает сам, вместо ваших определенных сопоставлений, даже для типов, для которых вы их явно определили. По крайней мере, с этим я столкнулся.

Быстрый способ проверить это: перейти на версию 6.1.1 и посмотреть, сохраняется ли проблема. В моем случае переход на более раннюю версию решил проблему.

У меня есть чувство, что должен быть лучший способ исправить это (или, может быть, это даже ошибка ...), но я пока не знаю, как это сделать. Если найду, отправлю сюда. Просто подумал, что я уже выбросил это здесь, если вам нужно быстрое исправление :)

AM создает карту для вас только тогда, когда не применяется существующая карта.

Lucian Bargaoanu 08.06.2018 19:22

@LucianBargaoanu Мой конструктор в моем профиле даже не вызывается в любое время от инициализации до момента, когда я вызываю Map для своих объектов. Кажется, что AutoMapper полностью игнорирует мой профиль, но когда я проверяю объект конфигурации, я вижу, что мой профиль зарегистрирован. Я собираюсь выбросить AutoMapper в окно. Что-то действительно напортачило в 7.x

crush 12.07.2018 19:41

Вы просто упускаете что-л. В противном случае вы могли бы создать суть, который мы можем выполнить и увидеть сбой.

Lucian Bargaoanu 12.07.2018 19:59

Одна вещь, которую нужно попробовать, - установить CreateMissingTypeMaps в false. Это упрощает понимание.

Lucian Bargaoanu 12.07.2018 20:09

Другие вопросы по теме