AutoMapper与DI嵌套映射

时间:2014-08-21 21:01:10

标签: c# .net automapper autofac

使用AutoMapper时,嵌套对象的映射非常简单,只要嵌套对象的Map定义也是如此。我遇到了在两个对象之间实现Map的问题,其中一个没有,也没有无参数构造函数。让我们说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); }
    }
}

如果有一个View Model,如下所示:

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

我们如何将Order Order映射到OrderViewModel,反之亦然?

1 个答案:

答案 0 :(得分:1)

OrderOrderViewModelOrderDetailsOrderDetailsViewModel应该是直截了当的:

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。在尝试这样做之前,我会阅读Jimmy Bogard's article on two way mapping。基本上创建AutoMapper是为了从域对象映射 DTO,而不是相反。

尽管如此,如果要映射回OrderOrderDetails,您可以使用AutoMapper使用IoC容器构建类型的能力。这涉及使用AutoMapper注册容器,以便它知道如何解析类型。

正如吉米在评论中指出的那样,您还需要注册OrderOrderDetails。我对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容器来创建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());

我认为这是一个不错的选择。感谢吉米·博加德在评论中指出了我正确的方向。