AutoMapper vs ValueInjecter [fechado]


209

Sempre que estou procurando coisas sobre o AutoMapper no StackOverflow, estou lendo algo sobre o ValueInjecter .

Alguém pode me dizer os prós e os contras entre eles (desempenho, recursos, uso da API, extensibilidade, teste)?


2
Outro que eu mencionei muito é o EmitMapper .
— precisa saber é o seguinte

1
E a cola? glue.codeplex.com Parece um ótimo projeto também, mas ainda não o testei. Eu vou durante o próximo mês, no entanto. Eu também vi um projeto chamado EmitMapper emitmapper.codeplex.com
— Trygve

Veja um artigo falando sobre essas duas ferramentas - devproconnections.com/development/…
— George

Respostas:


170

como criador do ValueInjecter , posso dizer que o fiz porque queria algo simples e muito flexível

Eu realmente não gosto de escrever muito ou escrever muito monkey codecomo:

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

ValueInjecter é algo como o mozilla com seus plugins, você cria ValueInjections e os usa

existem injeções embutidas para achatamento, desatamento e algumas que devem ser herdadas

e funciona mais de um tipo de aspecto , você não precisa especificar todas as propriedades 1 para 1; em vez disso, faz algo como:

pegue todas as propriedades int da fonte cujo nome termina com "Id", transforme o valor e defina cada uma como uma propriedade no objeto de origem com o mesmo nome sem o sufixo Id e seu tipo seja herdado da Entity, coisas assim

portanto, uma diferença óbvia, o ValueInjecter é usado mesmo em formulários de janelas com aplainamento e desatamento, é assim que flexível

(mapeamento do objeto para formar controles e voltar)

Automapper, não utilizável em formulários do Windows, sem desperdício, mas possui coisas boas, como o mapeamento de coleções, por isso, caso você precise dele com o ValueInjecter, basta fazer algo como:

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

você também pode usar o ValueInjecter para mapear objetos anônimos e dinâmicos

diferenças:

  • automapper criar configuração para cada possibilidade de mapeamento CreateMap ()

  • injetor de valor injetar de qualquer objeto para qualquer objeto (também existem casos em que você injeta do objeto para o tipo de valor)

  • O automapper construiu o achatamento, e apenas para tipos simples ou do mesmo tipo, e não possui desatamento

  • valueinjecter somente se você precisar dele você faz target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> e se você quiser a partir Foo.Bar.Name of type Stringde FooBarName of type Class1você herda FlatLoopValueInjection e especificar este

  • O automapper mapeia propriedades com o mesmo nome por padrão e, no restante, você deve especificar uma por uma e executar ações como Prop1.Ignore (), Prop2.Ignore () etc.

  • valueinjecter tem uma injeção padrão .InjectFrom () que faz as propriedades com o mesmo nome e tipo; para todo o resto, você cria suas injeções de valor personalizadas com regras / lógica de mapeamento individuais, mais como aspectos, por exemplo, de todos os adereços do Type Foo a todos os adereços do tipo Bar


5
Para o deus do amor, diga-me que o ValueInjector pode pegar um gráfico profundo do ViewModel e mapear para / de um gráfico profundo da Entidade de Negócios e mapear tudo o que é exatamente o mesmo, sem nenhum trabalho, e que eu só preciso especificar como lidar com o que é diferente. Eu esperava que o AutoMapper adicionasse esse recurso, mas ele nunca se materializou e não tive tempo de escrever meu próprio mapeador automático.
— Chris Marisic

3
@ Chris Marisic, você pode usá-lo, caso queira dizer clonagem profunda, fiz uma injeção uma vez que meio que faz isso recursivamente, mas não funciona para propriedades de coleções valueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126 , ou você pode criar um Flat ViewModel e usar o achatamento e o desatamento, isso seria fácil
— Omu

As entidades ViewModel e Domain seriam semelhantes, mas diferentes, portanto, não um clone puro. 90% das propriedades geralmente são do tipo e nome exatos, os ViewModels frequentemente terminam com SelectLists e itens vinculados a eles que eu gostaria de ignorar ao voltar ao domínio. É provável que ambos tenham coleções de objetos neles.
— Chris Marisic

27
<pedant>Parece legal, mas talvez seja ValueInjectOr? </pedant>
— Craig Stuntz

1
mas por alguma razão é er :)
— Omu

59

Como nunca usei nenhuma das outras ferramentas, só posso falar sobre o AutoMapper. Eu tinha alguns objetivos em mente para criar o AutoMapper:

  • Suporte ao achatamento para objetos DTO burros
  • Suporte cenários óbvios prontos para uso (coleções, enumerações etc.)
  • Poder verificar facilmente os mapeamentos em um teste
  • Permitir casos de borda para resolver valores de outros locais (tipo personalizado-> mapeamento de tipo, mapeamento de membro individual e alguns casos de borda realmente malucos).

Se você deseja fazer essas coisas, o AutoMapper funciona muito bem para você. As coisas que o AutoMapper não faz bem são:

  • Preenchendo Objetos Existentes
  • Desinteressante

A razão é que eu nunca precisei fazer essas coisas. Na maioria das vezes, nossas entidades não têm criadores, não expõem coleções, etc. é por isso que não existe. Usamos o AutoMapper para achatar para DTOs e mapear a partir de modelos de interface do usuário para comandar mensagens e similares. É aí que funciona muito, muito bem para nós.


1
@ Jimmy Bogard Você vê que o preenchimento de objetos existentes chegaria à lista de recursos do AutoMapper?
— Roman

Eu não tentei o ValueInjecter, mas pelo que precisamos, o automapper é muito poderoso.
— richb01

Eu acho que a coisa mais importante aqui é a verificabilidade. Ao renomear e refatorar coisas, isso é uma grande ajuda.
— Kugel

55

Eu tentei os dois e prefiro o ValueInjecter porque é muito simples:

myObject.InjectFrom(otherObject);

Isso é tudo o que há para saber sobre a grande maioria das minhas necessidades de injeção. Não pode ficar mais simples e elegante que isso.


1
this objectmétodo de extensão lá?
— Chris Marisic

2
Como eu poderia separar meu código do ValueInjecter? Para mim, parece haver sempre uma dependência do ValueInjecter, ou seja, no meu projeto da Web, porque eu uso o ValueInjecter (método de extensão) no objeto especificado DIRETAMENTE.
— Rookian

1
@Rookian, honestamente, isso não é uma preocupação em que você deve pensar muito. Você pode depender da interface mencionada pelo @Omu, portanto, se você mudar de mapeador, poderá economizar algum trabalho (provavelmente não muito). Esse tipo de dependência é muito difícil de abstrair, a menos que você queira entrar na AOP completa, que infelizmente é muitas vezes impossível de desfazer, pois o .NET não ajuda a fornecer suporte AOP corretamente. Agora você pode fazer um AOP fora de alguns dos mapeamentos, especialmente se você usar o MVC e escrever Action Filters que manipulam o mapeamento de ViewModel / DomainModel.
— Chris Marisic

13
por que um invólucro é a melhor solução? A única coisa que você precisa fazer se deseja alternar o mapeador é implementar o InjectFrom()método de extensão sozinho.
— jgauffin

1
Eu tentei os dois também e prefiro o AutoMapper. Usei-o para uma pequena parte do meu sistema, onde mapeio Entidades com classes geradas pelo Linq2Sql. O mapeamento simples como StockTotalQuantity -> stock_size_quantity ou UserId -> user_id funcionou com o AutoMapper por padrão. Não funcionou com o ValeInjecter, mesmo após adicionar convecção. Aderindo ao AutoMapper por enquanto.
— Artur Kędzior

27

Essa é uma pergunta que eu tenho pesquisado também e, para o meu caso de uso, parece ser um injetor de valor. Ele não requer configuração prévia para usar (acho que pode atingir o desempenho, embora, se implementado com inteligência, poderia armazenar em cache os mapeamentos para futuras invocações em vez de refletir a cada vez), portanto, você não precisa predefinir nenhum mapeamento antes de usá-los.

Mais importante ainda, ele permite o mapeamento reverso. Agora, posso estar faltando alguma coisa aqui, pois Jimmy menciona que ele não vê nenhum caso de uso quando necessário, então talvez eu tenha o padrão errado, mas meu caso de uso é que estou criando um objeto ViewModel a partir do meu ORM. Eu exibo isso na minha página da web. Depois que o usuário termina, recupero o ViewModel como um httppost, como isso é convertido novamente nas classes ORM originais? Eu adoraria conhecer o padrão com o automapper. Com o ValueInjector, é trivial e até desatento. por exemplo, criando uma nova entidade

O modelo criado pela entidadeframework (primeiro modelo):

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; }
}

O ViewModel (que eu posso decorar com 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; }
}

O 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();
        }
    }

Na minha opinião, não fica muito mais simples que isso?

(Então isso levanta a questão: o que há de errado com o padrão que eu me deparo com isso (e parece que muitos outros fazem), que não é visto como de valor para o AutoMapper?)

No entanto, se esse padrão, conforme descrito, for o que você deseja usar, meu voto será aplicado por milha do país.


1
provavelmente você também deve fazer isso em uma pergunta separada, marcada com asp.net-mvc e melhores práticas, ViewModel ..., atm Não vejo nenhum problema, desde que funcione bem para você, mas tenho certeza de que alguém pode ter opiniões diferentes
— Omu

Bem, tendo aprendido mais mvc. Agora posso responder minha pergunta. A maneira de atualizar o modelo original ao recuperar um modelo de vista preenchido é usar a função UpdateModel () que o mvc fornece.
— 6111 DanH

1
UpdateModel () é usado para preencher o modelo que representa a vista, e é o mesmo que fazer Ação (MyModelClasss modelo)
— Omu

É verdade, mas se você deseja ter um modelo de vista separado para, por exemplo, um modelo de repositório, ele pode ser usado para preencher a hipótese de que o mapeamento seja trivial (e geralmente é). É claro que se o ValueInjector mais complexo se resolver.
— DANH

1
Penso que se poderia argumentar que você não deve simplesmente definir suas propriedades novamente no modelo de domínio - você deve usar métodos que adicionem significado a ele.
— Mike Cole
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.