简体   繁体   English

带DI的AutoMapper嵌套映射

[英]AutoMapper nested mapping with DI

Mapping of nested objects is pretty straightforward with AutoMapper as long as there is a Map definition for the nested objects as well. 嵌套对象的映射使用AutoMapper非常简单,只要嵌套对象也有Map定义即可。 I am facing an issue with implementing a Map between 2 objects, one of which does not and cannot have a parameter-less constructor . 我在实现2个对象之间的Map时遇到了一个问题,其中一个对象没有且不能具有无参数构造函数 Let's say the Order object is such as below. 假设Order对象如下所示。 The services are injected by autofac constructor dependency injection. 通过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); }
    }
}

And if there was a View Model such as below: 如果存在如下所示的视图模型:

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; }
}

How would we go about Mapping Order to OrderViewModel and vice versa? 我们如何将订单映射到OrderViewModel,反之亦然?

Order to OrderViewModel and OrderDetails to OrderDetailsViewModel should be straightforward: OrderOrderViewModel和从OrderDetailsOrderDetailsViewModel应该很简单:

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))

The issue is mapping back to Order . 问题正在映射 Order Before attempting to do this, I would read Jimmy Bogard's article on two way mapping . 在尝试执行此操作之前,我将阅读Jimmy Bogard关于双向映射的文章 Basically AutoMapper was created to map to DTOs from domain objects, not the other way around. 基本上,AutoMapper的创建是为了从域对象映射 DTO,而不是相反。

Nevertheless, if you want to map back to Order and OrderDetails , you could use AutoMapper's ability to construct types using an IoC container. 但是,如果要映射回OrderOrderDetails ,则可以使用AutoMapper的功能来使用IoC容器构造类型。 This involves registering the container with AutoMapper so that it knows how to resolve types. 这涉及到在AutoMapper中注册容器,以便它知道如何解析类型。

As Jimmy points out in the comments, you'll also need to register Order and OrderDetails . 正如Jimmy在评论中指出的那样,您还需要注册OrderOrderDetails I'm not all that familiar with Autofac, but I had success with this: 我对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);

Now all you need to do is use .ReverseMap and .ConstructUsingServiceLocator to let AutoMapper know to use the IoC container to create the Order and OrderDetails objects: 现在,所有你需要做的是使用.ReverseMap.ConstructUsingServiceLocator让AutoMapper知道使用IoC容器创建OrderOrderDetails对象:

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());

I think this is a good option. 我认为这是一个不错的选择。 Thanks to Jimmy Bogard in the comments for pointing me in the right direction. 感谢Jimmy Bogard在评论中指出我的正确方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM