AutoMapper vs ValueInjecter [fermé]

209

Chaque fois que je cherche des trucs AutoMapper sur StackOverflow, je lis quelque chose sur ValueInjecter .

Quelqu'un peut-il me dire les avantages et les inconvénients entre eux (performances, fonctionnalités, utilisation de l'API, extensibilité, tests)?

Rookian
la source
2
Un autre que je vois beaucoup mentionné est EmitMapper .
adrianbanks
1
Et la colle? glue.codeplex.com Ressemble également à un grand projet, mais je ne l'ai pas encore essayé. Je le ferai cependant le mois prochain. J'ai également vu un projet appelé EmitMapper emitmapper.codeplex.com
Trygve
Voir un article parlant de ces deux outils - devproconnections.com/development/…
George Birbilis

Réponses:

170

en tant que créateur de ValueInjecter , je peux vous dire que je l'ai fait parce que je voulais quelque chose de simple et de très flexible

Je n'aime vraiment pas écrire beaucoup ou écrire beaucoup monkey codecomme:

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

ValueInjecter est quelque chose comme mozilla avec ses plugins, vous créez ValueInjections et les utilisez

il y a des injections intégrées pour aplatir, aplatir et certaines sont destinées à être héritées

et cela fonctionne plus dans un type d'aspect , vous n'avez pas besoin de spécifier toutes les propriétés 1 à 1, au lieu de cela, vous faites quelque chose comme:

prendre toutes les propriétés int de la source dont le nom se termine par "Id", transformer la valeur et définir chacune une propriété dans l'objet source avec le même nom sans le suffixe Id et son type est hérité d'Entity, des trucs comme ça

donc une différence évidente, ValueInjecter est utilisé même dans les formulaires Windows avec aplatissement et aplatissement, c'est à quel point il est flexible

(mappage de l'objet aux contrôles de formulaire et inversement)

Automapper, non utilisable dans les formulaires Windows, pas de non-aplatissement, mais il a de bonnes choses comme le mappage de collections, donc si vous en avez besoin avec ValueInjecter, vous faites juste quelque chose comme:

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

vous pouvez également utiliser ValueInjecter pour mapper à partir d' objets anonymes et dynamiques

différences:

  • automapper créer une configuration pour chaque possibilité de mappage CreateMap ()

  • injecteur de valeur injecte depuis n'importe quel objet vers n'importe quel objet (il y a aussi des cas où vous injectez de l'objet vers le type de valeur)

  • automapper a l'aplatissement construit, et uniquement pour les types simples ou du même type, et il n'a pas d'aplatissement

  • valueinjecter seulement si vous en avez besoin vous faites target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> et si vous voulez partir Foo.Bar.Name of type Stringpour FooBarName of type Class1vous héritez FlatLoopValueInjection et spécifiez cette

  • automapper mappe des propriétés avec le même nom par défaut et pour le reste, vous devez spécifier une par une, et faire des choses comme Prop1.Ignore (), Prop2.Ignore () etc.

  • valueinjecter a une injection par défaut .InjectFrom () qui fait les propriétés avec le même nom et le même type; pour tout le reste, vous créez vos injections de valeur personnalisées avec des logiques / règles de mappage individuelles, plus comme des aspects, par exemple de tous les accessoires de Type Foo à tous les accessoires de type Bar

Omu
la source
5
Pour le dieu de l'amour, dites-moi que ValueInjector peut prendre un graphique profond ViewModel et mapper vers / à partir d'une entité commerciale de graphique profond et mapper tout ce qui est exactement le même sans travail, et que je dois seulement spécifier comment gérer ce qui est différent. J'espérais qu'AutoMapper ajouterait cette capacité mais elle ne s'est jamais matérialisée et je n'ai pas eu le temps d'écrire mon propre mappeur automatique.
Chris Marisic
3
@Chris Marisic vous pouvez l'utiliser pour le faire, au cas où vous voulez dire un clonage en profondeur, j'ai fait une injection une fois que cela le fait récursivement mais ne fonctionne pas pour les propriétés des collections valueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126 , ou vous pouvez faire un Flat ViewModel et utiliser l'aplatissement et le non-aplatissement, ce serait facile
Omu
Le ViewModel et les entités de domaine seraient similaires mais différents, donc pas un pur clone. 90% des propriétés sont généralement de type et de nom exacts, les ViewModels se retrouvent souvent avec des SelectLists et des éléments qui leur sont liés que je voudrais ignorer en revenant au domaine. Les deux sont très susceptibles d'avoir des collections d'objets dessus.
Chris Marisic du
27
<pedant>Ça a l'air cool, mais ça devrait peut-être être ValueInjectOr? </pedant>
Craig Stuntz
1
mais pour une raison quelconque, c'est euh :)
Omu
59

Comme je n'ai jamais utilisé aucun des autres outils, je ne peux parler que d'AutoMapper. J'avais quelques objectifs en tête pour créer AutoMapper:

  • Prise en charge de l'aplatissement des objets DTO stupides
  • Prise en charge de scénarios évidents prêts à l'emploi (collections, énumérations, etc.)
  • Être capable de vérifier facilement les mappages dans un test
  • Autorisez les cas limites pour résoudre les valeurs d'autres endroits (mappage de type personnalisé> type, mappage de membre individuel et certains cas de bord vraiment fous).

Si vous voulez faire ces choses, AutoMapper fonctionne très bien pour vous. Les choses que AutoMapper ne fait pas bien sont:

  • Remplissage d'objets existants
  • Non aplatissant

La raison étant que je n'ai jamais eu besoin de faire ces choses. Pour la plupart, nos entités n'ont pas de setters, n'exposent pas de collections, etc. c'est pourquoi il n'y en a pas. Nous utilisons AutoMapper pour aplatir en DTO et mapper à partir de modèles d'interface utilisateur pour commander des messages et similaires. C'est là que cela fonctionne vraiment très bien pour nous.

Jimmy Bogard
la source
1
@Jimmy Bogard Voyez-vous que le remplissage d'objets existants arriverait jamais dans la liste des fonctionnalités d'AutoMapper?
Roman
Je n'ai pas essayé ValueInjecter, mais pour ce dont nous avons besoin, automapper est très puissant.
richb01
Je pense que la chose la plus importante ici est la vérifiabilité. Lorsque vous renommez et refactorisez des choses, cela est d'une grande aide.
Kugel
55

J'ai essayé les deux et préfère ValueInjecter car c'est si simple:

myObject.InjectFrom(otherObject);

C'est tout ce qu'il faut savoir pour la grande majorité de mes besoins en injection. Cela ne peut pas être plus simple et élégant que cela.

Adrian Grigore
la source
1
this objectméthode d'extension là-bas?
Chris Marisic
2
Comment puis-je découpler mon code de ValueInjecter? Pour moi, il semble qu'il y ait toujours une dépendance à ValueInjecter, c'est-à-dire dans mon projet Web, car j'utilise ValueInjecter (méthode d'extension) sur l'objet donné DIRECTEMENT.
Rookian
1
@Rookian, honnêtement, ce n'est pas une préoccupation à laquelle vous devriez réfléchir trop. Vous pouvez dépendre de l'interface comme @Omu mentionnée, donc si vous changez de mappeur, vous pourriez économiser du travail (probablement pas beaucoup). Ce type de dépendance est tout simplement trop difficile à résumer à moins que vous ne vouliez entrer dans un AOP complet qui est malheureusement souvent annulable, car .NET n'aide pas à fournir correctement le support AOP. Vous pouvez maintenant supprimer AOP une partie du mappage, surtout si vous utilisez MVC et écrivez des filtres d'action qui gèrent le mappage ViewModel / DomainModel.
Chris Marisic
13
pourquoi un emballage est-il la meilleure solution? La seule chose que vous devez faire si vous voulez changer de mappeur est d'implémenter la InjectFrom()méthode d'extension par vous-même.
jgauffin
1
J'ai également essayé les deux et je préfère AutoMapper. Je l'ai utilisé pour une petite partie de mon système où je mappe des entités avec des classes générées par Linq2Sql. Le mappage simple comme StockTotalQuantity -> stock_size_quantity ou UserId -> user_id fonctionnait avec AutoMapper par défaut. Cela n'a pas fonctionné avec ValeInjecter même après l'ajout de la convection. Rester sur AutoMapper pour l'instant.
Artur Kędzior
27

C'est une question que j'ai également recherchée, et pour mon cas d'utilisation, il semble que l'injecteur de valeur soit de loin. Il ne nécessite aucune configuration préalable à utiliser (peut affecter les performances, je suppose, bien que s'il est intelligemment mis en œuvre, il puisse mettre en cache les mappages pour les invocations futures plutôt que de les refléter à chaque fois), vous n'avez donc pas besoin de prédéfinir les mappages avant de les utiliser.

Mais surtout, il permet une cartographie inversée. Maintenant, je manque peut-être quelque chose ici car Jimmy mentionne qu'il ne voit aucun cas d'utilisation là où c'est nécessaire, alors peut-être que le modèle est incorrect, mais mon cas d'utilisation est que je crée un objet ViewModel à partir de mon ORM. Je l'affiche ensuite sur ma page Web. Une fois que l'utilisateur a terminé, je récupère le ViewModel en tant que httppost, comment cela est-il reconverti aux classes ORM d'origine? J'adorerais connaître le modèle avec automapper. Avec ValueInjector, c'est trivial, et il sera même aplati. ex: création d'une nouvelle entité

Le modèle créé par l'entitéframework (modèle d'abord):

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

Le ViewModel (que je peux décorer avec des validateurs):

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

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

À mon avis, cela ne devient pas beaucoup plus simple que cela?

(Donc, cela soulève la question, qu'est-ce qui ne va pas avec le modèle que je rencontre (et il semble que beaucoup d'autres le fassent), que ce n'est pas considéré comme ayant une valeur pour AutoMapper?)

Cependant, si ce modèle, tel que décrit, est celui que vous souhaitez utiliser, alors mon vote est injecteur de valeur par un mile du pays.

DanH
la source
1
vous devriez probablement aussi poser cette question dans une question distincte étiquetée avec asp.net-mvc et les meilleures pratiques, ViewModel ..., atm Je ne vois aucun problème tant que cela fonctionne bien pour vous, mais je suis sûr que quelqu'un pourrait avoir des opinions différentes
Omu
Bien avoir appris plus de mvc. Je peux maintenant répondre à ma question. La façon de mettre à jour le modèle d'origine lorsque vous récupérez un modèle de vue peuplé consiste à utiliser la fonction UpdateModel () fournie par mvc.
DanH
1
UpdateModel () est utilisé pour remplir le modèle qui représente la vue, et est identique à l'action (modèle MyModelClasss)
Omu
Certes, mais si vous souhaitez avoir un modèle de vue distinct pour, par exemple, un modèle de référentiel, il peut être utilisé pour indiquer que le mappage est trivial (et il l'est souvent). Bien sûr, si ValueInjector plus complexe prend tout son sens.
DanH
1
Je pense que l'argument pourrait être avancé selon lequel vous ne devriez pas simplement redéfinir vos propriétés sur votre modèle de domaine - vous devriez utiliser des méthodes qui lui donnent un sens.
Mike Cole