Можно ли отобразить несколько объектов DTO в один ViewModel с помощью Automapper? - PullRequest
18 голосов
/ 24 января 2010

Мне было интересно, возможно ли отобразить несколько объектов DTO в один объект ViewModel с помощью Automapper?

По сути, у меня есть несколько объектов DTO, и я хотел бы отображать информацию от каждого на одном экране в ASP.NET MVC 2.0. Для этого я бы хотел сгладить объекты DTO (или их части ...) в Viewmodel и передать указанную модель view в представление. Если бы у меня был один DTO, это было бы легко, но я никогда не видел, чтобы это делалось с несколькими. Очевидно, что есть несколько обходных способов сделать это (вне автопроизводителя), но я бы хотел использовать этот подход, если это возможно.

Ответы [ 6 ]

13 голосов
/ 19 января 2012

Проверьте следующую ссылку относительно вашего запроса

http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx

8 голосов
/ 21 мая 2015

Если у вас есть 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
7 голосов
/ 24 января 2010

Можно создать составной DTO, который содержит два или более объектов DTO, и сопоставить составной DTO с моделью выходного представления.

4 голосов
/ 14 ноября 2012

Вы можете добавить метод расширения переопределения Map из 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);
0 голосов
/ 11 апреля 2019

Это информация по просроченной ссылке в этом ответе: https://stackoverflow.com/a/8923063/2005596

При использовании 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);

    }
0 голосов
/ 08 июля 2016

Я сам все решил и нашел отличное решение. Скорее всего, ваши два представления как-то связаны в вашей системе (особенно если вы используете 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...