Ответ 1
Вы можете создать составной DTO, который содержит два или более объекта DTO и сопоставить составной DTO с моделью представления вывода.
Мне было интересно, можно ли сопоставить несколько объектов DTO с одним объектом ViewModel с помощью Automapper?
По сути, у меня есть несколько объектов DTO и вы хотите отображать информацию из каждого на одном экране в ASP.NET MVC 2.0. Для этого я хотел бы сгладить объекты DTO (или их части...) в Viewmodel и передать вид viewmodel в представление. Если бы у меня был один DTO, это было бы легко, но я никогда не видел, чтобы это делалось с несколькими. Очевидно, что существует ряд способов обхода (за пределами automapper), но это тот подход, который я хотел бы предпринять, если это возможно.
Вы можете создать составной DTO, который содержит два или более объекта DTO и сопоставить составной DTO с моделью представления вывода.
Проверьте следующую ссылку относительно вашего запроса
Если у вас есть 2 класса DTO и 1 сплющенная модель просмотра:
public class Dto1
{
public string Property1 { get; set; }
}
public class Dto2
{
public string Property2 { get; set; }
}
public class FlattenedViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
И вы создаете сопоставления для обоих DTO для просмотра модели:
CreateMap<Dto1, FlattenedViewModel>();
CreateMap<Dto2, FlattenedViewModel>();
Вы можете сопоставить 1-й DTO с моделью, а затем просто "добавить" 2-й DTO:
var dto1 = new Dto1 { Property1 = "Value1"; }
var dto2 = new Dto2 { Property2 = "Value2"; }
var model = Mapper.Map<FlattenedViewModel>(dto1); // map dto1 properties
Mapper.Map(dto2, model); // append dto2 properties
Вы можете добавить метод расширения переопределения карты из IMappingEngine, который принимает массив params. Что-то вроде:
public static class AutoMapperExtensions
{
public static T Map<T>(this IMappingEngine engine, params object[] sources) where T : class
{
if (sources == null || sources.Length == 0)
return default(T);
var destinationType = typeof (T);
var result = engine.Map(sources[0], sources[0].GetType(), destinationType) as T;
for (int i = 1; i < sources.Length; i++)
{
engine.Map(sources[i], result, sources[i].GetType(), destinationType);
}
return result;
}
}
Затем вы можете вызвать его следующим образом:
var result = Mapper.Engine.Map<MyViewModel>(dto1, dto2, dto3);
Я просто сам справился с этим и получил отличное решение. Скорее всего, ваши две точки зрения действительно связаны каким-то образом в вашей системе (особенно, если вы используете Entity Framework). Проверьте свои модели, и вы увидите что-то, что отображает отношения, если вы не просто добавите его. (virtual
)
Ваши модели
public class Dto1
{
public int id { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
public string Property5 { get; set; }
public virtual Dto2 dto2{ get; set; }
}
public class Dto2
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public string PropertyD { get; set; }
public string PropertyE { get; set; }
}
Ваши ViewModels
public class Dto1ViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public virtual Dto2VMForDto1 dto2{ get; set; }
}
//Special ViewModel just for sliding into the above
public class Dto2VMForDto1
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
Automapper выглядит так:
cfg.CreateMap< Dto1, Dto1ViewModel>();
cfg.CreateMap< Dto2, Dto2VMForDto1 >();
Я предполагаю, что вы получаете данные с LinQ:
Dto1ViewModel thePageVM = (from entry in context.Dto1 where...).ProjectTo<Dto1ViewModel>();
Виола, все будет работать. На ваш взгляд, просто доступ с помощью model.dto2.PropertyB
Это информация по просроченной ссылке в этом ответе: fooobar.com/info/282063/...
При использовании AutoMapper (http://automapper.codeplex.com) у меня часто возникает сценарий, когда мне нужно сопоставить несколько объектов в один объект. Обычно это происходит при отображении объектов из доменного числа в единую модель представления (ASP.NET MVC). К сожалению, API AutoMapper не предоставляет функциональные возможности для сопоставления нескольких объектов в один объект; однако для этого достаточно просто создать какой-нибудь вспомогательный метод. Ниже я проиллюстрирую подход, который я выбрал.
В этом примере у меня есть следующие объекты в моей доменной модели
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Country { get; set; }
}
public class Comment
{
public string Text { get; set; }
public DateTime Created { get; set; }
}
В дополнение к этому у меня есть требование отобразить сведения о человеке по адресу и обо всех комментариях на одной странице (используя ASP.NET MVC). Чтобы реализовать это, я создал модель представления, показанную ниже, которая включает в себя данные от всех трех сущностей домена, показанных выше
public class PersonViewModel
{
public int Id { get; set; }
[DisplayName("Firstname")]
public string Firstname { get; set; }
[DisplayName("Surname")]
public string Surname { get; set; }
[DisplayName("Address Line 1")]
public string AddressLine1 { get; set; }
[DisplayName("Address Line 2")]
public string AddressLine2 { get; set; }
[DisplayName("Country Of Residence")]
public string Country { get; set; }
[DisplayName("Admin Comment")]
public string Comment { get; set; }
}
В методе действия контроллера я делаю три отдельных вызова на уровне домена, чтобы получить требуемые сущности, но это все еще оставляет проблему, в которой мне нужно сопоставить несколько исходных сущностей в одну целевую сущность. Чтобы выполнить это отображение, я создал вспомогательный класс, который инкапсулирует AutoMapper и предоставляет функциональность, которая позволяет отображать несколько исходных объектов на один целевой объект. Этот класс показан ниже
public static class EntityMapper
{
public static T Map<T>(params object[] sources) where T : class
{
if (!sources.Any())
{
return default(T);
}
var initialSource = sources[0];
var mappingResult = Map<T>(initialSource);
// Now map the remaining source objects
if (sources.Count() > 1)
{
Map(mappingResult, sources.Skip(1).ToArray());
}
return mappingResult;
}
private static void Map(object destination, params object[] sources)
{
if (!sources.Any())
{
return;
}
var destinationType = destination.GetType();
foreach (var source in sources)
{
var sourceType = source.GetType();
Mapper.Map(source, destination, sourceType, destinationType);
}
}
private static T Map<T>(object source) where T : class
{
var destinationType = typeof(T);
var sourceType = source.GetType();
var mappingResult = Mapper.Map(source, sourceType, destinationType);
return mappingResult as T;
}
}
Чтобы отобразить несколько исходных объектов в одно место назначения, я использовал функциональность, предоставляемую AutoMapper, которая позволяет выполнять сопоставление между исходным объектом и объектом назначения, который уже существует.
Наконец, ниже приведен код контроллера, который извлекает три объекта и выполняет сопоставление с моделью одного представления.
public ActionResult Index()
{
// Retrieve the person, address and comment entities and
// map them on to a person view model entity
var personId = 23;
var person = _personTasks.GetPerson(personId);
var address = _personTasks.GetAddress(personId);
var comment = _personTasks.GetComment(personId);
var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment);
return this.View(personViewModel);
}