AutoMapper vs ValueInjecter [cerrado]

209

Cada vez que busco material de AutoMapper en StackOverflow, leo algo sobre ValueInjecter .

¿Alguien puede decirme los pros y los contras entre ellos (rendimiento, características, uso de API, extensibilidad, pruebas)?

Rookiano
fuente
2
Otro que veo mencionado mucho es EmitMapper .
adrianbanks
1
¿Qué pasa con el pegamento? glue.codeplex.com Parece un gran proyecto también, pero aún no lo he probado. Sin embargo, lo haré durante el próximo mes. También he visto un proyecto llamado EmitMapper emitmapper.codeplex.com
Trygve
Vea un artículo que habla sobre esas dos herramientas: devproconnections.com/development/…
George Birbilis

Respuestas:

170

Como creador de ValueInjecter , puedo decirte que lo hice porque quería algo simple y muy flexible

Realmente no me gusta escribir mucho o escribir muchos monkey codecomo:

Prop1.Ignore, Prop2.Ignore etc.
CreateMap<Foo,Bar>(); CreateMap<Tomato, Potato>(); etc.

ValueInjecter es algo así como Mozilla con sus complementos, crea ValueInjections y los usa

hay inyecciones incorporadas para aplanar, desaplanar y algunas que están destinadas a ser heredadas

y funciona más en un aspecto de tipo , no tiene que especificar todas las propiedades 1 a 1, en su lugar, hace algo como:

toma todas las propiedades int de la fuente cuyo nombre termina con "Id", transforma el valor y establece cada una en una propiedad en el objeto fuente con el mismo nombre sin el sufijo Id y su tipo se hereda de Entity, cosas así

Entonces, una diferencia obvia, ValueInjecter se usa incluso en formularios de Windows con aplanamiento y no aplanamiento, así de flexible es

(mapeo del objeto para formar controles y viceversa)

Automapper, no se puede usar en formularios de Windows, no se deshace, pero tiene cosas buenas como el mapeo de colecciones, por lo que en caso de que lo necesite con ValueInjecter simplemente haga algo como:

foos.Select(o => new Bar().InjectFrom(o));

También puede usar ValueInjecter para mapear desde objetos anónimos y dinámicos

diferencias:

  • configuración de creación de automapper para cada posibilidad de mapeo CreateMap ()

  • inyectar valueinjecter de cualquier objeto a cualquier objeto (también hay casos en los que inyecta de objeto a valuetype)

  • automapper tiene un aplanamiento construido, y solo para tipos simples o del mismo tipo, y no tiene aplanamiento

  • valueinjecter sólo si lo necesita lo hace target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> y si quieres de Foo.Bar.Name of type Stringque FooBarName of type Class1se hereda FlatLoopValueInjection y especifica este

  • automapper asigna propiedades con el mismo nombre de forma predeterminada y para el resto debe especificar una por una, y hacer cosas como Prop1.Ignore (), Prop2.Ignore () etc.

  • valueinjecter tiene una inyección predeterminada .InjectFrom () que realiza las propiedades con el mismo nombre y tipo; para todo lo demás, cree sus inyecciones de valores personalizados con lógica / reglas de mapeo individuales, más aspectos similares, por ejemplo, desde todos los accesorios de Type Foo hasta todos los accesorios de tipo Bar

Omu
fuente
55
Por el amor de Dios, dígame que ValueInjector puede tomar un ViewModel de gráfico profundo y asignarlo a / desde una Entidad de negocios de gráfico profundo y asignar todo lo que es exactamente lo mismo sin trabajo, y que solo necesito especificar cómo manejar qué es diferente. Esperaba que AutoMapper agregara esta capacidad, pero nunca se materializó y no he tenido tiempo de escribir mi propio mapeador automático.
Chris Marisic
3
@ Chris Marisic, puede usarlo, en caso de que quiera decir clonación profunda, hice una inyección una vez que hace esto de forma recursiva pero no funciona para las propiedades de colecciones valueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126 , o puede hacer un Flat ViewModel y usar el aplanamiento y el aplanamiento, esto sería fácil
Omu
Las entidades ViewModel y Domain serían similares pero diferentes, por lo que no serían un clon puro. El 90% de las propiedades suelen ser de tipo y nombre exactos, ViewModels con frecuencia terminan con SelectLists y cosas vinculadas a ellas que me gustaría ignorar al volver al dominio. Sin embargo, es muy probable que ambos tengan colecciones de objetos.
Chris Marisic
27
<pedant>Parece genial, pero tal vez debería ser ValueInjectOr? </pedant>
Craig Stuntz
1
pero por alguna razón es er :)
Omu
59

Como nunca he usado ninguna de las otras herramientas, solo puedo hablar sobre AutoMapper. Tenía algunas metas en mente para construir AutoMapper:

  • Admite aplanamiento a objetos DTO tontos
  • Admite escenarios obvios listos para usar (colecciones, enumeraciones, etc.)
  • Poder verificar fácilmente las asignaciones en una prueba
  • Permita casos límite para resolver valores de otros lugares (tipo personalizado-> mapeo de tipos, mapeo de miembros individuales y algunos casos extremos realmente locos).

Si desea hacer estas cosas, AutoMapper funciona muy bien para usted. Las cosas que AutoMapper no hace bien son:

  • Rellenar objetos existentes
  • Sin aplanamiento

La razón es que nunca he necesitado hacer estas cosas. En su mayor parte, nuestras entidades no tienen establecedores, no exponen colecciones, etc., por eso no está allí. Usamos AutoMapper para aplanar a DTO y mapear desde modelos de IU para mandar mensajes y similares. Ahí es donde funciona muy, muy bien para nosotros.

Jimmy Bogard
fuente
1
@Jimmy Bogard ¿Ves que llenar objetos existentes alguna vez llegaría a la lista de características de AutoMapper?
Romano
No he probado ValueInjecter, pero por lo que hemos necesitado, automapper es muy poderoso.
richb01
Creo que lo más importante aquí es la verificabilidad. Al renombrar y refactorizar las cosas, esto es de gran ayuda.
Kugel
55

Probé ambos y prefiero ValueInjecter porque es muy simple:

myObject.InjectFrom(otherObject);

Eso es todo lo que hay que saber para la gran mayoría de mis necesidades de inyección. No puede ser más simple y elegante que esto.

Adrian Grigore
fuente
1
this objectmétodo de extensión allí?
Chris Marisic
2
¿Cómo podría desacoplar mi código de ValueInjecter? Para mí, parece que siempre tengo una dependencia de ValueInjecter, es decir, en mi proyecto web, porque utilizo ValueInjecter (método de extensión) en el objeto dado DIRECTAMENTE.
Rookian
1
@Rookian honestamente, esta no es una preocupación en la que debas pensar demasiado. Podría depender de la interfaz como mencionó @Omu, por lo que si alguna vez cambia los mapeadores, podría ahorrar algo de trabajo (probablemente no mucho). Este tipo de dependencia es demasiado difícil de abstraer a menos que desee entrar en el AOP completo, que desafortunadamente muchas veces simplemente se puede deshacer, ya que .NET no ayuda a proporcionar el soporte de AOP correctamente. Ahora podría AOP eliminar parte de la asignación, especialmente si usa MVC y escribe filtros de acción que manejan la asignación de ViewModel / DomainModel.
Chris Marisic
13
¿Por qué un contenedor es la mejor solución? Lo único que debe hacer si desea cambiar el asignador es implementar el InjectFrom()método de extensión usted mismo.
jgauffin
1
He probado ambos también y prefiero AutoMapper. Lo usé para una pequeña parte de mi sistema donde mapeo Entidades con clases generadas por Linq2Sql. La asignación simple como StockTotalQuantity -> stock_size_quantity o UserId -> user_id funcionó con AutoMapper de forma predeterminada. No funcionó con ValeInjecter incluso después de agregar convección. Se adhiere a AutoMapper por ahora.
Artur Kędzior
27

Esta es una pregunta que también he estado investigando, y para mi caso de uso, parece ser un inyector de valor. No requiere una configuración previa para su uso (supongo que puede afectar el rendimiento, aunque si se implementa de manera inteligente podría almacenar en caché las asignaciones para invocaciones futuras en lugar de reflejar cada vez), por lo que no necesita predefinir ninguna asignación antes de usarlas.

Sin embargo, lo más importante es que permite el mapeo inverso. Ahora puede que me falte algo aquí, ya que Jimmy menciona que no ve ningún caso de uso cuando sea necesario, por lo que tal vez tenga el patrón incorrecto, pero mi caso de uso es que estoy creando un objeto ViewModel desde mi ORM. Luego muestro esto en mi página web. Una vez que el usuario finaliza, obtengo el ViewModel nuevamente como una publicación http, ¿cómo se vuelve a convertir a las clases ORM originales? Me encantaría conocer el patrón con automapper. Con ValueInjector es trivial e incluso se aplastará. por ejemplo, crear una nueva entidad

El modelo creado por el framework de entidad (modelo primero):

public partial class Family
{ 
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public virtual Address Address { get; set; }
}

public partial class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string TownCity { get; set; }
    public string County { get; set; }
    public string Postcode { get; set; }

    public virtual Family Family { get; set; }
}

El ViewModel (que puedo decorar con validadores):

public class FamilyViewModel
{
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public int AddressId { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string AddressTownCity { get; set; }
    public string AddressCounty { get; set; }
    public string AddressPostcode { get; set; }
}

El ViewController:

    //
    // GET: /Family/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Family/Create

    [HttpPost]
    public ActionResult Create(FamilyViewModel familyViewModel)
    {
        try
        {
            Family family = new Family();
            family.InjectFrom<UnflatLoopValueInjection>(familyViewModel);
            db.Families.Add(family);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

En mi opinión, ¿no es mucho más simple que eso?

(Entonces esto plantea la pregunta, ¿qué tiene de malo el patrón con el que me encuentro (y parece que muchos otros lo hacen), que no se considera de valor para AutoMapper?)

Sin embargo, si este patrón, tal como se describe, es uno que desea utilizar, entonces mi voto es un inyector de valor por milla de país.

DanH
fuente
1
probablemente también deberías hacer esto en una pregunta separada etiquetada con asp.net-mvc y las mejores prácticas, ViewModel ..., atm No veo ningún problema siempre que funcione bien para ti, pero estoy seguro de que alguien podría tener opiniones diferentes
Omu
Bueno, habiendo aprendido más mvc. Ahora puedo responder mi pregunta. La forma de actualizar el modelo original cuando recupera un modelo de vista poblado es utilizar la función UpdateModel () que proporciona mvc.
DanH
1
UpdateModel () se usa para llenar el modelo que representa la vista, y es lo mismo que hacer Action (modelo MyModelClasss)
Omu
Es cierto, pero si desea tener un modelo de vista separado para, por ejemplo, un modelo de repositorio, se puede usar para completar que asumir que la asignación es trivial (y a menudo lo es). Por supuesto, si ValueInjector más complejo entra en juego.
DanH
1
Creo que se podría argumentar que no debería simplemente restablecer sus propiedades en su modelo de dominio, sino que debería usar métodos que le agreguen significado.
Mike Cole