AutoMapper vs ValueInjecter [closed]
Asked Answered
L

4

208

Everytime I'm looking for AutoMapper stuff on StackOverflow, I'm reading something about ValueInjecter.

Can somebody tell me the pros and cons between them (performance, features, API usage, extensibility, testing) ?

Loverly answered 11/1, 2011 at 22:49 Comment(3)
Another one I see mentioned a lot is EmitMapper.Poncho
What about glue? glue.codeplex.com Looks like a great project as well, but I haven't tried it yet. I will during the next month though. I've also seen a project called EmitMapper emitmapper.codeplex.comSacred
See an article speaking about those two tools - devproconnections.com/development/…Annoying
E
169

as the creator of ValueInjecter, I can tell you that I did it because I wanted something simple and very flexible

I really don't like writing much or writing lots of monkey code like:

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

ValueInjecter is something like mozilla with it's plugins, you create ValueInjections and use them

there are built-in injections for flattening, unflattening, and some that are intended to be inherited

and it works more in an aspect type of way, you don't have to specify all properties 1-to-1, instead you do something like:

take all the int properties from source which name ends with "Id", transform the value and set each to a property in the source object with same name without the Id suffix and it's type is inherited from Entity, stuff like that

so one obvious difference, ValueInjecter is used even in windows forms with flattening and unflattening, that's how flexible it is

(mapping from object to form controls and back)

Automapper, not usable in windows forms, no unflatenning, but it has good stuff like collections mapping, so in case you need it with ValueInjecter you just do something like:

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

you can also use ValueInjecter to map from anonymous and dynamic objects

differences:

  • automapper create configuration for each mapping possibility CreateMap()

  • valueinjecter inject from any object to any object (there are also cases when you inject from object to valuetype)

  • automapper has flattening built it, and only for simple types or from same type, and it doesn't has unflattening

  • valueinjecter only if you need it you do target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> and if you want from Foo.Bar.Name of type String to FooBarName of type Class1 you inherit FlatLoopValueInjection and specify this

  • automapper maps properties with same name by default and for the rest you have to specify one by one, and do stuff like Prop1.Ignore(), Prop2.Ignore() etc.

  • valueinjecter has a default injection .InjectFrom() that does the properties with the same name and type; for everything else you create your custom valueinjections with individual mapping logic/rules, more like aspects, e.g. from all props of Type Foo to all props of type Bar

Embarrass answered 12/1, 2011 at 20:38 Comment(19)
For the love god please tell me ValueInjector can take a deep graph ViewModel and map to/from a deep graph Business Entity and map everything that is exactly the same with no work, and that I only need to specify how to handle whats different. I've been hoping AutoMapper would add this capability but it has never materialized and I haven't had the time to write my own auto mapper.Publication
@Chris Marisic you can use it do it, in case you mean deep cloning, I did one injection once that kinda does this recursively but doesn't work for collections properties valueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126, or you can do a Flat ViewModel and use the flattening and unflattening, this would be easyEmbarrass
The ViewModel and Domain Entities would be similar but different, so not a pure clone. 90% of properties are usually exact type and name, ViewModels frequently end up with SelectLists and stuff bound to them that I would want to ignore coming back to the domain. Both are very likely to have collections of objects on them though.Publication
@Chris Marisic there is a lot of this kind of stuff shown in the demos asp.net mvc demo, and unit tests, download it, play a bit with them and you will see how easy this isEmbarrass
I like the aspect way ;) But is this really only possible with ValueInjecter :o?Loverly
@Loverly well yes, unless automapper can do something like that, but I don't know that, maybe Jimmy will answer this questionEmbarrass
@Omu, ya that would be very interessting if he would soLoverly
@Embarrass what can you say about tesing or how to know that the destination object will be correctly filled?Loverly
@Loverly most of the time it's just obvious(always for me), but you can write a unit,a test and ensure it, automapper has a method that you can put in a unit test and ensure that your mapping configs are correct, like that you didn't forgot to specify some required configuration etc (vi doesn't require config so no method :) )Embarrass
<pedant> Looks cool, but perhaps it should be ValueInjectOr? </pedant>Mojgan
but for some reason it's er :)Embarrass
Isn't it actually: foos.Select(o => (Bar) new Bar().InjectFrom(o)); Since the signiture is object InjectFrom(this object target, object source); An possible improvement to eliminate the need for casting would be TTarget InjectFrom<TTarget>(this TTarget target, object source) where TTarget : class;Ebner
@Danny depending on the context it could be lots of different stuffEmbarrass
how do you map from one list to another list using valueinjecter?Chlamydate
@Chlamydate you use a foreach and do InjectFrom for every single object in the listEmbarrass
Thanks Chuck. That is what I am doing right now. is something like this planned for the future? where I wont have to iterate through each item in the list. At the moment I am writing a data layer and I want to be able to assign the results of my 'var records = {some linQ query}.ToList()' straight away to a matching custom dtoListObject. something like dtoListObject.InjectFrom(records); Any suggestions other than what you said above?Chlamydate
@Chlamydate you can always have your own custom class or some methods in a Utils class that do some custom mapping or add features that you needEmbarrass
Does VulueInjecter has anything parallel to Queryable projection support in Automapper?Splashy
I'm currently looking at which one to use, one thing that I can straight away see which might be relevant is AutoMapper looks like it is being updated on a regular basis wheras ValueInjecter has not been updated for nearly 3 years on NuGetTallman
F
59

Since I've never used any of the other tools, I can only talk about AutoMapper. I had a few goals in mind for building AutoMapper:

  • Support flattening to dumb DTO objects
  • Support obvious scenarios out of the box (collections, enumerations etc.)
  • Be able to easily verify mappings in a test
  • Allow for edge cases for resolving values from other places (custom type->type mapping, individual member mapping, and some really crazy edge cases).

If you want to do these things, AutoMapper works very well for you. Things AutoMapper doesn't do well are:

  • Filling existing objects
  • Unflattening

The reason being I've never needed to do these things. For the most part, our entities don't have setters, don't expose collections, etc. so that's why it's not there. We use AutoMapper to flatten to DTOs and map from UI models to command messages and the like. That's where it works really, really well for us.

Formalism answered 30/3, 2011 at 2:10 Comment(3)
@Jimmy Bogard Do you see that Filling existing objects would ever make it to the feature list for AutoMapper?Incapacious
I haven't tried ValueInjecter, but for what we've needed, automapper is very powerful.Ayo
I think the most important thing here is the verifiability. When renaming and refactoring things this is a huge help.Bantling
N
54

I tried both and prefer ValueInjecter because it's so simple:

myObject.InjectFrom(otherObject);

That's all there is to know for the vast majority of my injection needs. It can't possibly get more simple and elegant than this.

Navigation answered 12/1, 2011 at 21:7 Comment(9)
this object extension method there?Publication
How could I decouple my code from ValueInjecter? For me it seems like to have always a depedency to ValueInjecter i.e. in my web project, because I use ValueInjecter (extension method) on the given object DIRECTLY.Loverly
@Loverly you could also use the IValueInjecter interface instead of the static extension, and do injecter.Inject(myObject, otherObject) valueinjecter.codeplex.com/documentationEmbarrass
@Loverly honestly this isn't a concern you should place too much thought into. You could depend on the interface like @Embarrass mentioned so if you ever change mappers you might save some work (probably not much). This type of a dependency is just too hard to abstract away unless you want to get into full blown AOP which is unfortunately many times just undoable since .NET doesn't help provide AOP support correctly. Now you could AOP away some of the mapping, especially if you use MVC and write Action Filters that handle ViewModel / DomainModel mapping.Publication
@Loverly you can also create your own mapper class as a wrapper for injecting stuffEmbarrass
yes a wrapper would be the best option in my opinionLoverly
why is a wrapper the best solution? The only thing you need to do if you want to switch mapper is to implement the InjectFrom() extension method by yourself.Erwinery
@Erwinery yes, this is also a good option :)Loverly
I have tried both as well and I do prefer AutoMapper. I used it for a small part of my system where I map Entities with Linq2Sql generated classes. Simple mapping as StockTotalQuantity -> stock_size_quantity or UserId -> user_id did work with AutoMapper by default. It didn't work with ValeInjecter even after adding convetion. Sticking to AutoMapper for now.Somersault
U
27

This is a question I've been researching too, and for my use case, it seems to be valueinjecter hands down. It requires no prior setup to use (may hit performance I guess, although if smartly implemented it could cache the mappings for future invocations rather than reflecting each time), so you don't need to predefine any mappings before using them.

Most importantly however, it allows reverse mapping. Now I may be missing something here as Jimmy mentions that he sees no use case where its necessary, so maybe I have the pattern wrong, but my use case is that I'm creating a ViewModel object from my ORM. I then display this on my webpage. Once the user finishes I get the ViewModel back in as a httppost, how does this get converted back to the original ORM classes? I'd love to know the pattern with automapper. With ValueInjector it is trivial, and it will even unflatten. e.g Creating a new entity

The model created by the entityframework (model first):

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

The ViewModel (which I can decorate with validators):

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

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

To my mind, it doesn't get much simpler than that?

(So this begs the question, whats wrong with the pattern that I run into this (and it seems many others do to), that its not seen as of value to AutoMapper?)

However, if this pattern as decscribed, is one you want to use, then my vote is valueinjecter by a country mile.

Ulland answered 15/4, 2011 at 3:31 Comment(9)
probably you should also ask this in a separate question tagged with asp.net-mvc and best-practices, ViewModel ..., atm I don't see any problem as long as it works well for you, but I'm sure that somebody might have different opinionsEmbarrass
Well having learnt more mvc. I can now answer my question. The way to update the original model when you get a populated view model back, is to use the UpdateModel() function mvc provides.Ulland
UpdateModel() is used to populate the Model that represents the view, and is the same as doing Action(MyModelClasss model)Embarrass
True, but if you want to have a seperate view model to for example a respository model, then it can be used to populate that assuming the mapping is trivial (and it often is). Of course if more complex ValueInjector comes into its own.Ulland
I think the solution that I am about to propose may not belong this thread. However here's what I would do. I would delegate this job to the business services. So the MVC knows nothing about Data Model it only knows about Domain Model. The business services talks to both data model and domain model and do the unidirectional conversions using the Automapper or ValueInjector or your own custom mapper.Vaporish
I think the argument could be made that you shouldn't simply set your properties back on your domain model - you should use methods that add meaning to it.Warila
Have to say that I've moved away from this injection pattern as I built out the tiers of my web app. So mostly using methods to change data in the backend rather than passing around objects. This may be a result of not using an ORM though...Ulland
@Ulland - I think your 2nd paragrah and initial sentiment holds true regardless of the UpdateModel method if your underlying there are more than 1 underlying model class comprising your ViewModel correct?Zane
Sure it's valid if it fits your use case. Mostly I find projection for removing fields I don't want to send to the client or compositing up data, and if going Json style then these days I find I'm using linq to select into an anon class unless it would be reused in multiple places. When round tripping data back to the server it's normally a simpler model anyway, e.g. A form rather than a complex page model coming back. So the update model/inbound binding approach is normally up to the task.Ulland

© 2022 - 2024 — McMap. All rights reserved.