Наследование AutoMapper и Linq
Я искал, как использовать Inheritance в AutoMapper
, но я изо всех сил стараюсь полностью работать с Linq
. Вот мой код:
Я определил свои отображения здесь:
CreateMap<Article, ArticleDetailsViewModel>()
.Include<Article, ArticleNewsItemDetailsViewModel();
CreateMap<Article, ArticleNewsItemDetailsViewModel>();
ArticleDetailsViewModel
является базовым классом ArticleNewsItemDetailsViewModel
.
Теперь вот проблема, если бы у меня было:
CreateMap<ArticleNewsItem, ArticleNewsItemDetailsViewModel>();
Все свойства в модели представления будут автоматически отображаться, потому что они имеют то же имя, что и их эквивалент объекта Linq. Однако, потому что я использую сопоставление Article => ArticleNewsItemDetailsViewModel
, это невозможно, вместо этого я должен был бы определить каждый из них как:
.ForMember(x => x.Property1, opt => opt.MapFrom(src => src.ArticleNewsItem.Property1)
Я подумал о переносе всех свойств из ArticleNewsItemDetailsViewModel
в новую модель представления и присвоении этому классу свойства внутри ArticleNewsItemDetailsViewModel
и пока есть сопоставление между этими двумя объектами, тогда оно будет работать, но оно не работает, t чувствую себя очень чистым.
Есть ли способ избежать этого?
Ответы
Ответ 1
Предположим, что у вас есть следующие классы:
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; }
}
Отображение должно выглядеть следующим образом:
var res = Mapper.Map<Article, ArticleNewsItemDetailsViewModel>(_article);
Mapper.Map(_article.ArticleNewsItem, res);
Кроме того, вы можете создать преобразователь пользовательского типа, чтобы избежать записи этих двух строк каждый раз, когда вам нужно сопоставить Article
с ArticleNewsItemDetailsViewModel
.
Ответ 2
Извиняюсь, если я больше упрощаю это в своей голове, но вы не можете просто добавить указанное прямое сопоставление:
CreateMap<ArticleNewsItem, ArticleNewsItemDetailsViewModel>();
Для меня это самое простое и чистое решение...
ИЗМЕНИТЬ
Извините, я неправильно понял. Вы не можете сопоставить объект с вложенным свойством, не создавая настраиваемую карту через методы .ConstructUsing() или .ConvertUsing() (или делать это неопрятный путь)...
Mapper.CreateMap<Article, ArticleNewsItemDetailsViewModel>().ConstructUsing(ConstructItem)
.. Затем создайте свой метод для создания объекта 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;
}
Однако я бы порекомендовал повторно реализовать ваше решение, чтобы вы отображали "как будто". Вот хороший пример: http://automapper.codeplex.com/wikipage?title=Nested%20Mappings
Ответ 3
Предполагая, что все необходимые свойства находятся в статье, вы можете создать Custom Value Resolver, чтобы сделать это, например.
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>());