WedX - журнал о программировании и компьютерных науках

Почему я получаю отсутствующую конфигурацию карты типа или ошибку неподдерживаемого сопоставления в automapper?

Код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;

namespace TestAutomapper
{
  class Program
  {
    static void Main(string[] args)
    {

      var config = new MapperConfiguration(cfg => cfg.CreateMap<MyClassSource, MyClassDestination>());


      var mapper = config.CreateMapper();

      var source = new MyClassSource { DateTimeValue = null };

      var mapped = mapper.Map<MyClassSource, MyClassDestination>(source);
    }

  }

  public class MyClassSource
  {
    public object DateTimeValue { get; set; }
  }

  public class MyClassDestination
  {
    public DateTime? DateTimeValue { get; set; }
  }
}

Ошибка:

    AutoMapper.AutoMapperMappingException was unhandled
      HResult=-2146233088
      Message=Error mapping types.

    Mapping types:
    MyClassSource -> MyClassDestination
    TestAutomapper.MyClassSource -> TestAutomapper.MyClassDestination

    Type Map configuration:
    MyClassSource -> MyClassDestination
    TestAutomapper.MyClassSource -> TestAutomapper.MyClassDestination

    Property:
    DateTimeValue
      Source=Anonymously Hosted DynamicMethods Assembly
      StackTrace:
           at lambda_method(Closure , MyClassSource , MyClassDestination , ResolutionContext )
           at TestAutomapper.Program.Main(String[] args) in C:\Users\costa\documents\visual studio 2015\Projects\TestAutomapper\TestAutomapper\Program.cs:line 22
           at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
      InnerException: 
           HResult=-2146233088
           Message=Missing type map configuration or unsupported mapping.

    Mapping types:
    Object -> Nullable`1
    System.Object -> System.Nullable`1[[System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
           Source=Anonymously Hosted DynamicMethods Assembly
           StackTrace:
                at lambda_method(Closure , Object , Nullable`1 , ResolutionContext )
                at lambda_method(Closure , MyClassSource , MyClassDestination , ResolutionContext )
           InnerException: 

Я думал, что эта ошибка устранена (https://github.com/AutoMapper/AutoMapper/issues/1095< /а>). Я использую Automapper 5.1.1.

Как это исправить?

Спасибо

Изменить: просто чтобы уточнить, меня беспокоит обработка нулевого значения. Я понимаю, что преобразование ненулевого значения объекта в DateTime сложно. В реальном коде фактическое значение в исходном объекте равно null или DateTime. Я думал, что null обрабатывается без ошибок.

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

Я создал метод расширения ToDate для преобразования объекта в дату и добавил это сопоставление для обработки преобразований из объекта в DateTime?:

cfg.CreateMap<object, DateTime?>().ConstructUsing(src => src.ToDate());

  • Прошло некоторое время с тех пор, как я использовал AutoMapper, но я считаю, что для автоматического сопоставления одного и того же имени свойства с разными типами требуется сопоставление между двумя типами (например, object и DateTime?). Так что либо добавьте сопоставление между object и DateTime? (что кажется странным), либо используйте пользовательские параметры разрешения. 17.10.2016

Ответы:


1

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

Вам нужно определить, как вы хотите разрешить DateTime? имущество. Это будет работать:

var config = new MapperConfiguration(
    cfg =>
    {
        cfg.CreateMap<MyClassSource, MyClassDestination>()
            .ForMember(
                destination => destination.DateTimeValue,
                memberOptions => memberOptions.ResolveUsing(sourceMember =>
                {
                    DateTime dateTime;
                    return !DateTime.TryParse(sourceMember.DateTimeValue.ToString(), out dateTime) ? (DateTime?) null : dateTime;
                }));
    }
);

Если ваш исходный элемент является допустимым объектом даты и времени, он будет преобразован в дату и время, в противном случае целевое свойство получит нулевое значение.

17.10.2016
  • Это удивительно, потому что null является допустимым значением для DateTime? переменная. Следующий код: PropertyInfo pi = typeof(MyClassDestination).GetProperty("DateTimeValue"); MyClassDestination dst = new MyClassDestination(); pi.SetValue(dst, null); работает нормально. 18.10.2016
  • Верно. Но я думаю, что ключ в том, что хотя null является допустимым значением для DateTime? свойство, вы не можете гарантировать, что оно всегда будет нулевым, поскольку исходное свойство является объектом. Таким образом, он может иметь любое другое недопустимое значение, отсюда и ошибка. Что делать, если значением исходного свойства является Foo (строка)? 18.10.2016
  • Я с тобой согласен. Однако я думал, что automapper предоставляет некоторые процедуры преобразования по умолчанию, которые, по крайней мере, обрабатывают нулевые значения (если место назначения допускает значение null) или значения совместимых типов. 18.10.2016
  • @costa Вы путаете значение источника с типом источника. Хотя Automapper действительно может правильно сопоставить значение null, он не может в общем случае сопоставить какой-либо объект со значением DateTime?, поэтому он терпит неудачу, потому что между этими двумя типами не определено сопоставление. Проблема, на которую вы ссылаетесь, не работает при сопоставлении между двумя свойствами одного и того же типа, допускающего значение NULL, который отличается. 18.10.2016
  • @DStanley: не думаю, что я их путаю. Я ожидал, что во время выполнения automapper обеспечивает какое-то преобразование по умолчанию. В данном конкретном случае целевым свойством является DateTime? а исходным свойством является объект. Я ожидал, что автомаппер выполнит как минимум следующий код (грубо - в псевдокоде): if (source value is null and destination property type is nullable) then return null; if (source value type is the same as the destination property type) then return original value; и т.д... 18.10.2016
  • @costa Такого сопоставления по умолчанию не существует. Карты являются статическими и не зависят от значений времени выполнения. На мой взгляд, они не должны этого делать, потому что это может скрыть недопустимые карты только потому, что некоторые значения времени выполнения могут быть преобразованы. 18.10.2016
  • @DStanley: сопоставления по умолчанию существуют, иначе автосопоставление не работало бы «из коробки». Я думаю, вы имеете в виду сопоставления по умолчанию между, казалось бы, несовместимыми типами, такими как object -> DateTime?. Я согласен с вами более или менее :-) Если вы присваиваете значение DateTime (DateTime.Now) исходному DateTimeValue, сопоставление работает. Если вы назначите DateTime.Now.ToString(), это также сработает. Таким образом, есть какое-то сопоставление по умолчанию, но это сопоставление по умолчанию не может обрабатывать нули. Это мое утверждение. 18.10.2016
  • @costa Да, это то, что я имел в виду - сопоставление по умолчанию между несовместимыми типами. Я удивлен, что сопоставление работает, если источник содержит ненулевой DateTime. 18.10.2016
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]