ediblecode
ediblecode

Reputation: 11971

AutoMapper inheritance and Linq

I've been looking over how to use Inheritance in AutoMapper but I'm struggling to get it working fully with Linq. Here is my code:

I have defined my mappings here:

CreateMap<Article, ArticleDetailsViewModel>()
    .Include<Article, ArticleNewsItemDetailsViewModel();

CreateMap<Article, ArticleNewsItemDetailsViewModel>();

ArticleDetailsViewModel is a base class of ArticleNewsItemDetailsViewModel.

Now here lies the problem, if I had:

CreateMap<ArticleNewsItem, ArticleNewsItemDetailsViewModel>();

All of the properties in the view model would automatically map because they are the same name as their Linq object counterpart. However, because I am using the Article => ArticleNewsItemDetailsViewModel mapping this is not possible, instead I would have to define each one as:

.ForMember(x => x.Property1, opt => opt.MapFrom(src => src.ArticleNewsItem.Property1)

I thought about moving all properties from ArticleNewsItemDetailsViewModel into a new view model and having that class a property within the ArticleNewsItemDetailsViewModel and as long as there is a mapping between those two objects then it will work, but it doesn't feel very clean.

Is there any way to avoid having to do this?

Upvotes: 20

Views: 1257

Answers (3)

James
James

Reputation: 82096

Assuming all the required properties are in Article you could create a Custom Value Resolver to do this e.g.

public class ArticleNewsItemResolver : ValueResolver<Article, ArticleNewsItem>
{
    protected override ArticleNewsItem ResolveCore(Article source)
    {
        return Mapper.DynamicMap<Article, ArticleNewsItem>(source);
    }
}
...

CreateMap<Article, ArticleNewsItemDetailsViewModel>()
    .ForMember(src => src.NewsItem, opt => opt.ResolveUsing<ArticleNewsItemResolver>());

Upvotes: 0

k0stya
k0stya

Reputation: 4315

Supposing you have the following classes:

    public class Article
    {
        public string Prop1 { get; set; }
        public string Prop2 { get; set; }
        public ArticleNewsItem ArticleNewsItem { get; set; }
    }

    public class ArticleDetailsViewModel
    {
        public string Prop1 { get; set; }
    }

    public class ArticleNewsItemDetailsViewModel : ArticleDetailsViewModel
    {
        public string Prop2 { get; set; }
        public string Prop3 { get; set; }
    }

    public class ArticleNewsItem
    {
        public string Prop3 { get; set; }
    }

The mapping should look like below:

var res = Mapper.Map<Article, ArticleNewsItemDetailsViewModel>(_article);
Mapper.Map(_article.ArticleNewsItem, res);

Moreover you can create custom type converter to avoid writing these two lines every time you need to map Article to ArticleNewsItemDetailsViewModel.

Upvotes: 1

NinjaNye
NinjaNye

Reputation: 7126

Apologies if I am over simplifying this in my head but can't you simply add the direct mapping you mention:

CreateMap<ArticleNewsItem, ArticleNewsItemDetailsViewModel>();

To me this is the simplest and cleanest solution...

EDIT Sorry, I misunderstood. You can't map an object to a nested property without creating a custom map via .ConstructUsing() or .ConvertUsing() methods (or doing it the untidy way)...

Mapper.CreateMap<Article, ArticleNewsItemDetailsViewModel>().ConstructUsing(ConstructItem)

..Then create your method to build the ArticleNewsItemDetailsViewModel...

private static ArticleNewsItemDetailsViewModel ConstructItem(Article source)
    {
        var newsItem = new ArticleNewsItem
                           {
                               Prop1 = source.Prop1,
                               Prop2 = source.Prop2
                           };

        var result = new ArticleNewsItemDetailsViewModel()
                         {
                             ArticleNewsItem = newsItem
                         };

        return result;
    }

However I would still recommend re implementing your solution so you are mapping 'like for like'. Here is a good example: http://automapper.codeplex.com/wikipage?title=Nested%20Mappings

Upvotes: 0

Related Questions