簡體   English   中英

帶DI的AutoMapper嵌套映射

[英]AutoMapper nested mapping with DI

嵌套對象的映射使用AutoMapper非常簡單,只要嵌套對象也有Map定義即可。 我在實現2個對象之間的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); }
    }
}

如果存在如下所示的視圖模型:

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,反之亦然?

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

問題正在映射 Order 在嘗試執行此操作之前,我將閱讀Jimmy Bogard關於雙向映射的文章 基本上,AutoMapper的創建是為了從域對象映射 DTO,而不是相反。

但是,如果要映射回OrderOrderDetails ,則可以使用AutoMapper的功能來使用IoC容器構造類型。 這涉及到在AutoMapper中注冊容器,以便它知道如何解析類型。

正如Jimmy在評論中指出的那樣,您還需要注冊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());

我認為這是一個不錯的選擇。 感謝Jimmy Bogard在評論中指出我的正確方向。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM