Noocyte’s Weblog

October 13, 2011

AutoMapper, aka AutoMagic

Filed under: Work — Tags: , , — noocyte @ 14:30

 

Update 27.10.2011: It turns out that the implementation below is not really all that good. The map created with the custom resolver will be cached; so all future results from a mapping process will use the initial value (enityTwoId). I reverted to ignoring the property during the mapping and then setting it manually afterwards.

We are currently working on a re-write of an application here at Proactima and in that process I’ve decided to use EF 4.1 Magic Unicorn Edtion as my backend. It supports POCOs, but sometimes I don’t really wanna send the whole object to the view; so I create some view specific classes to use for this purpose. Mapping between the entity class and the view class would be tedious work was it not for the magic of AutoMapper! It handles the RHS-LHS mapping for me! How cool! But sometimes even magic needs a helping hand and AutoMapper accepts it!

These are my entity classes (not the actual classes…):

public class EntityOne
{
    public int EntityOneID { get; set; }
    public string Title { get; set; }
    public virtual ICollection<EntityTwo> EntityTwos { get; set; }
}

public class EntityTwo
{
    public int EntityTwoID { get; set; }
    public string SomeInformation { get; set; }
    public int EntityOneID { get; set; }
    public virtual EntityOne EntityOne { get; set; }
}

And these should be mapped to these classes:

public class EntityOneView
{
    public int EntityOneID { get; set; }
    public string Title { get; set; }
    public virtual EntityTwoView EntityTwo { get; set; }
}

public class EntityTwoView
{
    public int EntityTwoID { get; set; }
    public string SomeInformation { get; set; }  
}

Basically I only bring with me one of the “EntityTwoView” objects, as opposed to a list in the entity class. Naturally in an actual application the classes would be FAR more complex than these, but I needed this to illustrate the point. I find it easier to understand code where there is little or no noise.

Given an “EntityOne” object I now want to map/convert it to an “EntityOneView” object before sending it of the the view (from the controller in ASP.Net MVC). If I didn’t have to list->one issue I could simply write these two lines:

EntityOne one = db.Load<EntityOne>(1);
Mapper.CreateMap<EntityOne, EntityOneView>();
EntityOneView oneView = Mapper.Map<EntityOneView>(one);

But this will fail since AutoMapper have no idea on how to go from a list of EntityTwo’s to a single EntityTwo. So I have to help her (?) out a bit. I can do that by writing a Custom Value Resolver. It would for this code look like this:

public class SingleLineResolver : ValueResolver<EntityOne, EntityTwoView>
{
    private int EntityTwoId { get; set; }
    public SingleLineResolver(int entityTwoId)
    {
        this.EntityTwoId = entityTwoId;
    }

    protected override EntityTwoView ResolveCore(EntityOne source)
    {
        Mapper.CreateMap<EntityTwo, EntityTwoView>();
        var line = source.EntityTwos.First(e=> e.EntityTwoID == this.EntityTwoId);
        return Mapper.Map<EntityTwoView>(line);
    }
}

This code took me awhile to understand and be able to write… Now I might be stupid and you smart, so perhaps I’m the only one struggeling with this one… But to make use of it I had to update the previous code to:

EntityOne one = new EntityOne();
SingleLineResolver resolver = new SingleLineResolver(2);
Mapper.CreateMap<EntityOne, EntityOneView>()
    .ForMember(dest => dest.EntityTwo, opt => opt.ResolveUsing(resolver));
EntityOneView oneView = Mapper.Map<EntityOneView>(one);

Here I am basically saying that when you (AutoMapper) create the mapping between EntityOne and EntityOneView and come to the “EntityTwo” property (on the EntityOneView object) please use my custom value resolver (resolver) to figure out the value of that property. It will then send the “one” object into my custom value resolver class (SingleLineResolver) and the output will be set as the value of the property called “EntityTwo” on the new object of type “EntityOneView”; Puh!

Basically AutoMapper let’s me use two objects (or more!) that are fairly similar and map between them. She (?) will handle complex scenarios like this and much, much more. I hereby dub the project “AutoMagic”.

Please note that the code I present here has been severly altered from the actual production code, so please don’t shoot me if it fails to work as expected!

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.