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)?

Rookian
fonte
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

Omu
fonte
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.

Jimmy Bogard
fonte
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.

Adrian Grigore
fonte
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.

DanH
fonte
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