2015-08-06 2 views
1

rI знаю два инструмента: значение инжектора и автомаппер. Каждый из них в настоящее время поддерживает одну из функций, которые мне действительно нужны. :) Справочная информация. Я использую хранимую процедуру для загрузки данных из БД. отношения 1 ко многим обрабатываются как свойства XML. Рассмотрим следующий примерMapper, поддерживающий оба: «отображение из xml» и «unflattening»

public class AutorDto 
    { 
     public string Name { get; set; } 
     public List<Post> Posts { get; set; } 
     public ICity City { get; set; } 
    } 
    public interface ICity 
    { 
     string Name { get; set; } 
     string Code { get; set; } 
    } 
    public class CityDto 
    { 
     public string Name { get; set; } 
     public string Code { get; set; } 
    } 

    public class PostDto 
    { 
     public DateTime Date { get; set; } 
     public string Content { get; set; } 
    } 

Я хранимую процедуру, которая будет возвращать мне эту структуру в следующей схеме:

public class Autor_From_Stored_Procedure 
    { 
     public string Name { get; set; } 
     public string Posts { get; set; } 
     public string CityName { get; set; } 
     public string CityCode { get; set; } 
    } 

Чтобы отобразить Autor_From_Stored_Procedure в AutorDto мы должны обрабатывать две темы:

  1. Deserializing from XML (мне удалось справиться с этой проблемой с помощью automapper. Я использовал эту тему: Automapper to create object from XML) и эту статью: http://www.codeproject.com/Articles/706992/Using-AutoMapper-with-Complex-XML-Data

  2. Unflattening. Кажется, что AutoMapper не поддерживает unflattening на основе соглашения. Это правда ? Я видел, что существует возможность объявить некоторую строку (например, «Город») как объект Unflattened, и все должно работать, но значение инжектора предлагает это как стандарт на основе конвекции: objectToIll.InjectFrom < UnflatLoopInjection> (объект) - без необходимости для объявить, какие свойства [имена в конкретном] будут deflattened). Это также возможно с automapper?

Если нет, то, возможно, я должен сосредоточиться на значении инжектора. Если это так - проблема с 1) точки остается в силе (надеюсь, она решена так же легко, как и в automapper)

Penny для ваших мыслей!

@@ Обновление

Я изменил DTO определение добавляющего интерфейс для города (как это мой случай)

+0

Я думаю, что на первом этапе все, что нужно это XML десериализатор, не картостроитель – Omu

+0

@Omu, я пришел к такому же выводу (сейчас я пользуюсь ValueInjecter) Тем не менее у меня проблема с базовым отображением объектов (unflattening). Используя приведенный выше пример: Mapper.AddMap (SRC => { Var Рез = новый AutorDto(); res.InjectFrom (ЦСИ); // XML пользовательские привязки возврата Рез; }); \t \t \t \t Недвижимость City on Autor - это интерфейс (ICity). Я получаю сообщение об ошибке: «Невозможно создать экземпляр интерфейса». Как с этим справиться? –

+0

UnflatLoopInjection предполагает, что все ваши свойства unflattening являются объективными и без параметров конструктора atm, поэтому вы можете не использовать Unflat, изменять типы свойств или захватывать исходный код – Omu

ответ

1

Я отправлю anwser на мой вопрос - может быть, это поможет кому-то. Я перешел из Automapper в Valueinjecter. Xml-привязка была выполнена с использованием пользовательской AddMap() и с использованием XmlSerializer (здесь нет магии)

Но оказывается, что будет проблема с интерфейсом на классе «Autor» (и deflattening). Вы не можете просто создать экземпляр интерфейса, и это была проблема. Я изменил немного valueinjecter Tunnelier для обработки такого случая.

Во-первых, я попытался покрыть это, используя какое-то соглашение (если вы находите свойство ISomething, вырезаем «Я» добавляю «Dto». Но это не изящное решение. Поэтому у меня получилось обычай: сопоставление Inteface + Class (так я указываю: если вы видите интерфейс ISomething, создайте экземпляр SomethingDto) Вот модифицированный код (возможно, это может быть добавлено к реализации valueinjecter?) Основной класс «Mapper» не является частичным, поэтому я определил новый класс для эти отображения:

namespace Omu.ValueInjecter 
{ 
    public partial class MapperActivations 
    { 
     public static ConcurrentDictionary<Type, Type> InterfaceActivations = new ConcurrentDictionary<Type, Type>(); 
     public static void AddInterfaceActivation<Interface, Class>() 
     { 
      InterfaceActivations.AddOrUpdate(typeof(Interface), typeof(Class), (key, oldValue) => typeof(Class)); 
     } 
    } 
} 

Вот модифицированные классы valueInjected:

public static class TunnelierCustom 
    { 
     public static PropertyWithComponent Digg(IList<string> trail, object o) 
     { 
      var type = o.GetType(); 
      if (trail.Count == 1) 
      { 
       return new PropertyWithComponent { Component = o, Property = type.GetProperty(trail[0]) }; 
      } 

      var prop = type.GetProperty(trail[0]); 

      var val = prop.GetValue(o); 

      if (val == null) 
      { 
       if (prop.PropertyType.IsInterface) 
       { 
        if (MapperActivations.InterfaceActivations.ContainsKey(prop.PropertyType)) 
        { 
         val = Activator.CreateInstance(MapperActivations.InterfaceActivations[prop.PropertyType]); 
        } 
        else 
        { 
         throw new Exception("Unable to create instance of: " + prop.PropertyType.Name + ". Are you missing InterfaceActivations bidning? Please add it using MapperActivations.AddInterfaceActivation<Interface, Class>() statement"); 
        } 
       } 
       else 
       { 
        val = Activator.CreateInstance(prop.PropertyType); 
       } 
       prop.SetValue(o, val); 
      } 

      trail.RemoveAt(0); 
      return Digg(trail, val); 
     } 

     public static PropertyWithComponent GetValue(IList<string> trail, object o, int level = 0) 
     { 
      var type = o.GetType(); 

      if (trail.Count == 1) 
      { 
       return new PropertyWithComponent { Component = o, Property = type.GetProperty(trail[0]), Level = level }; 
      } 

      var prop = type.GetProperty(trail[0]); 
      var val = prop.GetValue(o); 
      if (val == null) return null; 
      trail.RemoveAt(0); 
      return GetValue(trail, val, level + 1); 
     } 
    } 

    /// <summary> 
    /// performs flattening and unflattening 
    /// first version of this class was made by Vadim Plamadeala ☺ 
    /// </summary> 
    public static class UberFlatterCustom 
    { 
     public static IEnumerable<PropertyWithComponent> Unflat(string flatPropertyName, object target, Func<string, PropertyInfo, bool> match, StringComparison comparison) 
     { 
      var trails = TrailFinder.GetTrails(flatPropertyName, target.GetType().GetProps(), match, comparison, false).Where(o => o != null); 

      return trails.Select(trail => TunnelierCustom.Digg(trail, target)); 
     } 

     public static IEnumerable<PropertyWithComponent> Unflat(string flatPropertyName, object target, Func<string, PropertyInfo, bool> match) 
     { 
      return Unflat(flatPropertyName, target, match, StringComparison.Ordinal); 
     } 

     public static IEnumerable<PropertyWithComponent> Unflat(string flatPropertyName, object target) 
     { 
      return Unflat(flatPropertyName, target, (upn, pi) => upn == pi.Name); 
     } 

     public static IEnumerable<PropertyWithComponent> Flat(string flatPropertyName, object source, Func<string, PropertyInfo, bool> match) 
     { 
      return Flat(flatPropertyName, source, match, StringComparison.Ordinal); 
     } 

     public static IEnumerable<PropertyWithComponent> Flat(string flatPropertyName, object source, Func<string, PropertyInfo, bool> match, StringComparison comparison) 
     { 
      var trails = TrailFinder.GetTrails(flatPropertyName, source.GetType().GetProps(), match, comparison).Where(o => o != null); 

      return trails.Select(trail => TunnelierCustom.GetValue(trail, source)); 
     } 

     public static IEnumerable<PropertyWithComponent> Flat(string flatPropertyName, object source) 
     { 
      return Flat(flatPropertyName, source, (up, pi) => up == pi.Name); 
     } 
    } 

    public class UnflatLoopCustomInjection : ValueInjection 
    { 
     protected override void Inject(object source, object target) 
     { 
      var sourceProps = source.GetType().GetProps(); 
      foreach (var sp in sourceProps) 
      { 
       Execute(sp, source, target); 
      } 
     } 

     protected virtual bool Match(string upn, PropertyInfo prop, PropertyInfo sourceProp) 
     { 
      return prop.PropertyType == sourceProp.PropertyType && upn == prop.Name; 
     } 

     protected virtual void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp) 
     { 
      tp.SetValue(target, sp.GetValue(source)); 
     } 

     protected virtual void Execute(PropertyInfo sp, object source, object target) 
     { 
      if (sp.CanRead) 
      { 
       var endpoints = UberFlatterCustom.Unflat(sp.Name, target, (upn, prop) => Match(upn, prop, sp)).ToArray(); 

       foreach (var endpoint in endpoints) 
       { 
        SetValue(source, endpoint.Component, sp, endpoint.Property); 
       } 
      } 
     } 
    } 

И это пример использования:

 MapperActivations.AddInterfaceActivation<ICity, City>(); 
     Mapper.AddMap<Auto_From_Stored_Procedure, AutorDto>(src => 
      { 
       var res = new User(); 
       res.InjectFrom<UnflatLoopCustomInjection>(src); 
       res.Posts = Mapper.Map<XElement, List<Posts>>(src.PostsXml , "PostDto"); //this is mapping using XmlSerializer, PostsXml is XElement.Parse(Posts) in Autor_From_Stored_Procedure. 
       return res; 
      }); 
0

новая версия была выпущена 3.1

теперь вы можете указать параметр активатора для UnflatLoopInjection

взглянуть на эту unit test

Смежные вопросы