Reputation: 11971
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
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
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
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