Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

Ответ 3

Если у вас есть 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

Ответ 4

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

Ответ 5

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

Ответ 6

Это информация по просроченной ссылке в этом ответе: 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);

    }