[英]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,反之亦然?
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
。 在嘗試執行此操作之前,我將閱讀Jimmy Bogard關於雙向映射的文章 。 基本上,AutoMapper的創建是為了從域對象映射到 DTO,而不是相反。
但是,如果要映射回Order
和OrderDetails
,則可以使用AutoMapper的功能來使用IoC容器構造類型。 這涉及到在AutoMapper中注冊容器,以便它知道如何解析類型。
正如Jimmy在評論中指出的那樣,您還需要注冊Order
和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());
我認為這是一個不錯的選擇。 感謝Jimmy Bogard在評論中指出我的正確方向。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.