使用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,反之亦然?
答案 0 :(得分: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
。在尝试这样做之前,我会阅读Jimmy Bogard's article on two way mapping。基本上创建AutoMapper是为了从域对象映射到 DTO,而不是相反。
尽管如此,如果要映射回Order
和OrderDetails
,您可以使用AutoMapper使用IoC容器构建类型的能力。这涉及使用AutoMapper注册容器,以便它知道如何解析类型。
正如吉米在评论中指出的那样,您还需要注册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());
我认为这是一个不错的选择。感谢吉米·博加德在评论中指出了我正确的方向。