AutoMapper вложенного отображения с DI

1

Отображение вложенных объектов довольно просто с помощью AutoMapper, пока есть определение карты для вложенных объектов. Я столкнулся с проблемой при реализации Карты между двумя объектами, одна из которых не имеет и не может иметь конструктор без параметров. Предположим, что объект Order является таким, как показано ниже. Сервисы вводятся путем интродукции зависимостей конструктора autofac.

public class Order
{
    private readonly IOrderDetailsService _orderDetailsService;

    public Order(IOrderDetailsService orderDetailsService)
    {
        _orderDetailsService = orderDetailsService;
    }

    public string Name { get; set; }
    public int Id { get; set; }

    [NonSerialized] private IEnumerable<OrderDetails> _details;

    public IEnumerable<OrderDetails> Details
    {
        get
        {
            _details = _orderDetailsService.GetDetailsByOrderId(Id);
            return _details;
        }
        set { _details = value; }
    }

}

public class OrderDetails
{
    private readonly IOrderService _orderService;
    public OrderDetails(IOrderService orderService)
    {
        _orderService = orderService;
    }

    public int OrderId { get; set; }
    public int DetailId { get; set; }
    public string DetailInfo { get; set; }

    public Order Order
    {
        get { return _orderService.GetOrderById(OrderId); }
    }
}

И если была модель просмотра, например, ниже:

public class OrderViewModel
{
    public string OrderName { get; set; }
    public int OrderId { get; set; }
    public IEnumerable<OrderDetailsViewModel> Details { get; set; } 
}

public class OrderDetailsViewModel
{
    public int DetailId { get; set; }
    public string DetailInformation { get; set; }
}

Как мы будем использовать порядок сопоставления OrderViewModel и наоборот?

  • 0
    Я обновил свой ответ - пожалуйста, дайте мне знать, если это лучше, чем мои предыдущие решения.
Теги:
autofac
automapper

1 ответ

1
Лучший ответ

Order на OrderViewModel и OrderDetails на OrderDetailsViewModel должен быть простым:

Mapper.CreateMap<Order, OrderViewModel>()       
    .ForMember(dest => dest.OrderName, opt => opt.MapFrom(src => src.Name))
    .ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id));

Mapper.CreateMap<OrderDetails, OrderDetailsViewModel>()     
    .ForMember(dest => dest.DetailInformation, opt => opt.MapFrom(src => src.DetailInfo))

Проблема связана с обращением к Order. Прежде чем пытаться это сделать, я бы прочитал статью Джимми Богара о двухстороннем картографировании. В основном AutoMapper был создан для сопоставления DTO с объектами домена, а не наоборот.

Тем не менее, если вы хотите вернуться к Order and OrderDetails, вы можете использовать способность AutoMapper для создания типов с использованием контейнера IoC. Это включает регистрацию контейнера с помощью AutoMapper, чтобы он знал, как разрешать типы.

Как указывает Джимми в комментариях, вам также необходимо зарегистрировать Order and OrderDetails. Я не так хорошо знаком с Autofac, но у меня был успех:

var builder = new ContainerBuilder();

builder.RegisterType<OrderDetailsService>().As<IOrderDetailsService>();
builder.RegisterType<OrderService>().As<IOrderService>();

/* Register Order and OrderDetails to use themselves: */
builder.RegisterType<Order>().AsSelf();
builder.RegisterType<OrderDetails>().AsSelf();

var container = builder.Build();

/* Register the container with AutoMapper */
Mapper.Configuration.ConstructServicesUsing(container.Resolve);

Теперь все, что вам нужно сделать, это использовать .ReverseMap и .ConstructUsingServiceLocator чтобы AutoMapper знал, использовать контейнер IoC для создания объектов Order и OrderDetails:

Mapper.CreateMap<Order, OrderViewModel>()       
    .ForMember(dest => dest.OrderName, opt => opt.MapFrom(src => src.Name))
    .ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id))
    .ReverseMap()
    .ConstructUsingServiceLocator()
    .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.OrderId))
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.OrderName))
    .ForMember(dest => dest.Details, opt => opt.Ignore());

Mapper.CreateMap<OrderDetails, OrderDetailsViewModel>()     
    .ForMember(dest => dest.DetailInformation, opt => opt.MapFrom(src => src.DetailInfo))
    .ReverseMap()
    .ConstructUsingServiceLocator()     
    .ForSourceMember(dest => dest.DetailInformation, opt => opt.Ignore())
    .ForMember(dest => dest.DetailInfo, opt => opt.Ignore());

Я думаю, что это хороший вариант. Спасибо Джимми Богарду в комментариях за то, что он указал мне в правильном направлении.

  • 0
    Поскольку у Order и OrderDetails нет конструктора без параметров, я не вижу, как будет работать второй подход (предложенный вами). Обращается ли это каким-либо образом, что не упомянуто?
  • 0
    Хм, хорошо, я обратился к Order но вы правы насчет OrderDetails Думаю, второй подход не сработает.
Показать ещё 15 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню