2015-03-04 4 views
6

У меня есть следующие классы домена и DTO классы:Использование AutoMapper для отображения строки в перечислении

public class Profile 
{ 
    public string Name { get; set; } 
    public string SchoolGrade { get; set; } 
} 

public class ProfileDTO 
{ 
    public string Name { get; set; } 
    public SchoolGradeDTO SchoolGrade { get; set; } 
} 

public enum SchoolGradeDTO 
{ 
    [Display(Name = "Level One"] 
    LevelOne, 
    [Display(Name = "Level Two"] 
    LevelTwo, 
} 

Я использовал следующий метод:

Mapper.CreateMap<Profile, ProfileDTO>() 
     .ForMember(d => d.SchoolGrade , op => op.MapFrom(o => o.SchoolGrade)) 

После этого, я получаю следующее сообщение об ошибке:

Requested value 'Level Two' was not found.

Как правильно его сопоставить?

+0

Любая причина, по которой вы передаете значение атрибута отображения для перечисления? То есть почему вы используете «Level Two» вместо «LevelTwo». Это делает задачу намного сложнее (для ее устранения потребуется разрешение). – Umair

+0

Использование 'LevelTwo' позволит автоматически отображать карту памяти (не нужно бит' ForMember') – Umair

+0

В чем вопрос? –

ответ

11

Поскольку вы картографирование от имени отображения и не перечисления имени вам нужно Buid пользовательской функции отображения для сканирования атрибутов, чтобы найти перечисление с таким именем дисплея. Вы можете использовать ResolveUsing вместо MapFrom использовать пользовательскую функцию отображения:

Mapper.CreateMap<Profile, ProfileDTO>() 
     .ForMember(d => d.SchoolGrade, 
       op => op.ResolveUsing(o=> MapGrade(o.SchoolGrade))); 

public static SchoolGradeDTO MapGrade(string grade) 
{ 
    //TODO: function to map a string to a SchoolGradeDTO 
} 

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

Несколько способов сделать это можно найти here.

6

Расширяя ответ D Stanley «s сверху в немного более подробно, и модифицировал EnumHelper class from this other discussion сосредоточиться на конкретной ситуации, поскольку этот вопрос действительно охватывает две области, AutoMapper и правильно получить значение перечисления от строки.

Повышение D Stanley «s оригинального ответа:

public static class QuestionAutoMapperConfig 
{ 
    public static void ConfigureAutoMapper() 
    { 
     Mapper.CreateMap<Profile, ProfileDTO>() 
      .ForMember(d => d.SchoolGrade, 
       op => op.ResolveUsing(o => MapGrade(o.SchoolGrade))); 
    } 

    public static SchoolGradeDTO MapGrade(string grade) 
    { 
     //TODO: function to map a string to a SchoolGradeDTO 
     return EnumHelper<SchoolGradeDTO>.Parse(grade); 
    } 
} 

Я скорректировал EnumHelper из указанного примера, чтобы быстро показать вариант, где с помощью вы можете изменить метод Синтаксического сначала попробовать стандартную Enum. Parse() и не удается выполнить более подробное сравнение типа Enum путем создания словаря значений, основанных либо на имени имени перечисления, либо на его текстовом атрибуте (если используется).

public static class EnumHelper<T> 
{ 
    public static IDictionary<string, T> GetValues(bool ignoreCase) 
    { 
     var enumValues = new Dictionary<string, T>(); 

     foreach (FieldInfo fi in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public)) 
     { 
      string key = fi.Name; 

      var display = fi.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[]; 
      if (display != null) 
       key = (display.Length > 0) ? display[0].Name : fi.Name; 

      if (ignoreCase) 
       key = key.ToLower(); 

      if (!enumValues.ContainsKey(key)) 
       enumValues[key] = (T)fi.GetRawConstantValue(); 
     } 

     return enumValues; 
    } 

    public static T Parse(string value) 
    { 
     T result; 

     try 
     { 
      result = (T)Enum.Parse(typeof(T), value, true); 
     } 
     catch (Exception) 
     { 
      result = ParseDisplayValues(value, true); 
     } 


     return result; 
    } 

    private static T ParseDisplayValues(string value, bool ignoreCase) 
    { 
     IDictionary<string, T> values = GetValues(ignoreCase); 

     string key = null; 
     if (ignoreCase) 
      key = value.ToLower(); 
     else 
      key = value; 

     if (values.ContainsKey(key)) 
      return values[key]; 

     throw new ArgumentException(value); 
    } 
} 
Смежные вопросы