22

I am currently using AutoMapper to map my Entity Framework entities to my View Model:

public class ProductsController : Controller
{
    private IProductRepository productRepository;

    public ProductsController(IProductRepository productRepository)
    {
         this.productRepository = productRepository;
    }

    public ActionResult Details(int id)
    {
        var product = productRepository.GetProduct(id);

        if( product == null )
            return View("NotFound");

        ProductDetailsViewModel model = Mapper.Map<Product, ProductDetailsViewModel>(product);

        return View(model);
    }
}

This works well. The question I have is when I need to go from my View Model to my entity in order to update the database. Should I be using AutoMapper for this? Is this a bad/dangerous practice?

It seems like AutoMapper is good for flattening a complex type to a simple (flat) type, but so far I'm struggling trying to go from a flat/simple to a more complex type like my entity with the various navigation properties.

If it is a bad idea to use AutoMapper to do this, then what would my code look like for a Create action?

public ActionResult Create(CreateProductViewModel model)
{
    if( ModelState.IsValid )
    {
        // what do i do here to create my Product entity?
    }
}

What about an Edit action?

public ActionResult Edit(int id, EditProductViewModel model)
{
    Product product = productRepository.GetProduct(id);

    // how do i convert my view model to my entity at this point???
}
Dismissile
  • 32,564
  • 38
  • 174
  • 263
  • your viewmodels could have a property of the entity Product, that way you won't need to convert at all. – Joakim Sep 28 '11 at 20:05
  • This article offers a few suggestions. http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ – jrummell Sep 28 '11 at 20:10

4 Answers4

29

I'm a of the mindset that updating your entities is a pretty big deal and that no automated tool should ever be used. Set the properties manually.

Yes its a very tiny amount of more code but automapper or running updatemodel on database entities can sometimes have unintended consequences. Better to make sure your writes are done correctly.

John Farrell
  • 24,673
  • 10
  • 77
  • 110
  • I'm fine with this, but this kind of makes my controller beyond ugly. I'm of the mindset that the controller should be as simple as possible (only a few lines long). Should I just suck it up? :) – Dismissile Sep 28 '11 at 20:10
  • +1. Automapper and its ilk are great for flattening entities to viewmodels, but you need to put a bit more thought into updating entities. – Ian Nelson Sep 28 '11 at 20:11
  • 5
    @Dismissile - so don't put the code in the controller. Create a class responsible for converting between viewmodels and entities, and call that from the controller. Makes testing easier and adheres to SRP. – Ian Nelson Sep 28 '11 at 20:12
  • 12
    You know that you can customize the mappings to do exactly what you want it to do for each property. I don't really see a difference between this and writing your own assignment statements. For simple property to property mappings I think it works well. – tvanfosson Sep 28 '11 at 20:13
  • 3
    +1 to jfar. Tell don't ask. Using automapper is asking if you ask me. Also keep it as simple as possible and kick out as many framework dependencies as possible. – Deleted Sep 28 '11 at 20:27
  • 1
    @tvanfosson - That's more work than the seconds it takes to write `Model.Property = ViewModel.Property` – John Farrell Sep 29 '11 at 14:21
  • Using AutoMapper puts an extremely opaque layer between your domain and presentation layers. "Visual Studio: rename `Domain.Entity.Property`". Congratulations: your view models are now broken because of their implicit use of `Property`. – ta.speot.is Nov 25 '13 at 00:54
  • Use an extension method to convert your domain model (entity) to your view model. PRO TIP: if you are using linq to query, create your extension method on the IQueryable – Donuts Oct 14 '14 at 18:47
12

I use AutoMapper with a specialized mapping class that understands how to make a complex model from a simple one. AutoMapper is used to handle the one-to-one mapping and the custom logic in the class for doing the more complex things (like relationships, etc.). All of the AutoMapper configuration is done in the static constructor for the mapping class, which also validates the mapping configuration so that errors fail early.

public class ModelMapper
{
    static ModelMapper()
    {
        Mapper.CreateMap<FooView,Foo>()
              .ForMember( f => f.Bars, opt => opt.Ignore() );

        Mapper.AssertConfigurationIsValid();
    }

    public Foo CreateFromModel( FooView model, IEnumerable<Bar> bars )
    {
         var foo = Mapper.Map<FooView,Foo>();
         foreach (var barId in model.BarIds)
         {
             foo.Bars.Add( bars.Single( b => b.Id == barId ) );
         }
         return foo;
    }
}
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
2

Essentially automapping is bad, I wrote a blog post on this http://blog.gavryli.uk/2015/12/02/why-automapping-is-bad-for-you/

Ivan G.
  • 5,027
  • 2
  • 37
  • 65
  • 3
    The link in the answer is broken, the new one seems to be https://ivanazure.wordpress.com/2015/12/02/why-automapping-is-bad-for-you/ Why all the downvotes? The article gives great arguments against automapping. – Gebb Apr 10 '17 at 09:27
  • 1
    great alternative perspective on the downsites of automapping, don't worry about the downvotes. I would suggest to include some of your points in your answer. – Felix K. Apr 09 '19 at 22:24
2

You could also try configuring AutoMapper to only map Scalar properties (instead of having to .Ignore() every single property you don't want it to (including inherited properties like .EntityKey and .EntityState).

AutoMapper.Mapper.CreateMap<EntityType, EntityType>()
    .ForAllMembers(o => {
         o.Condition(ctx =>
             {
                 var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping

                if (!members.Any())
                    return false;
                return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set
            });
    });

Some more info at http://www.prosoftnearshore.com/blog/post/2012/03/14/Using-AutoMapper-to-update-Entity-Framework-properties.aspx

Mauricio Morales
  • 988
  • 1
  • 9
  • 16