我需要使用 AutoMapper 将一个对象映射到另一个对象。棘手的问题是如何访问映射配置内部或自定义类型转换器内部的映射器实例(IMapper 实例)?
下面的代码不起作用,但它是我想要实现的示例 - 请注意
mapper.Map
调用并假设映射 Customer => CustomerDto
和 Customer => DetailedCustomerDto
已定义。
var config = new MapperConfiguration(
cfg => cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing(o => {
return o.Type == 1
? mapper.Map<Customer, CustomerDto>(o.Customer)
: mapper.Map<Customer, DetailedCustomerDto>(o.Customer)
})
);
客户端部分是:
var mapper = config.CreateMapper();
var orderDto = mapper.Map<Order, OrderDto>(order);
我想要映射的对象的简化版本是:
public class Order
{
public int Type { get; set; }
public Customer Customer { get; set; }
}
public class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}
public class OrderDto
{
public CustomerDto Customer { get; set; }
}
public class CustomerDto
{
public long Id { get; set; }
}
public class DetailedCustomerDto : CustomerDto
{
public string Name { get; set; }
}
从上面的代码中可以看出,根据
Order.Type
的值,映射器应该将属性 Order.Customer
映射到不同的目标。由于一个目标 (DetailedCustomerDto
) 继承了另一个目标 (CustomerDto
),这就变得有点棘手。
请注意,不能选择使用过时且已弃用的静态方法 Mapper.Map 。
自 AutoMapper 8.0 及更高版本起
下面 5.1.1 的答案仍然适用,只是
ResolveUsing
已重命名为 MapFrom
;代表签名保持不变。
自 AutoMapper 5.1.1 起
您可以使用
ResolveUsing
的重载来访问映射器,它接受具有四个参数的委托,最后一个参数是 ResolutionContext
,它具有 Mapper
属性(下面代码片段中的 context.Mapper
):
var config = new MapperConfiguration(
cfg => {
cfg.CreateMap<Customer, CustomerDto>();
cfg.CreateMap<Customer, DetailedCustomerDto>();
cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing(
(order, orderDto, i, context) => {
return order.Type == 1
? context.Mapper.Map<Customer, CustomerDto>(order.Customer)
: context.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
}));
});
var orderTypeOne = new Order();
orderTypeOne.Type = 1;
orderTypeOne.Customer = new Customer() {
Id = 1
};
var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));
var orderTypeTwo = new Order();
orderTypeTwo.Type = 2;
orderTypeTwo.Customer = new Customer() {
Id = 1
};
dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));
AutoMapper 5.1.1 之前
您可以使用带有两个参数的
ResolveUsing
重载来访问映射器,第一个是 ResolutionResult
(result.Context.Engine.Mapper
):
var config = new MapperConfiguration(
cfg => {
cfg.CreateMap<Customer, CustomerDto>();
cfg.CreateMap<Customer, DetailedCustomerDto>();
cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing((result, order) => {
return order.Type == 1
? result.Context.Engine.Mapper.Map<Customer, CustomerDto>(order.Customer)
: result.Context.Engine.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
}));
});
var orderTypeOne = new Order();
orderTypeOne.Type = 1;
orderTypeOne.Customer = new Customer() {
Id = 1
};
var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));
var orderTypeTwo = new Order();
orderTypeTwo.Type = 2;
orderTypeTwo.Customer = new Customer() {
Id = 1
};
dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));
我正在使用
Automapper 9
,上面的答案对我不起作用。
然后为了解决像你一样的问题,我使用 .afterMap
,就像这样:
public class AutoMapperOrder : Profile
{
public AutoMapperOrder()
{
CreateMap<Customer, CustomerDto>()
//...
CreateMap<Customer, DetailedCustomerDto>()
//...
CreateMap<Order, OrderDto>()
.AfterMap((src, dest, context) => {
dest.Customer = src.Type == 1
? context.Mapper.Map<Customer, CustomerDto>(src.Customer)
: context.Mapper.Map<Customer, DetailedCustomerDto>(src.Customer)
}
}
}
}
我希望能帮助别人。
除了 Evk 对我有帮助的很好的答案之外,如果您需要在需要自定义构造函数的配置/配置文件内的映射内进行映射(即该类型没有默认构造函数),则以下内容将在 v5.2.0 中工作:
CreateMap<Models.Job, Models.API.Job>(MemberList.Source);
CreateMap<StaticPagedList<Models.Job>, StaticPagedList<Models.API.Job>>()
.ConstructUsing((source, context) => new StaticPagedList<Models.API.Job>(
context.Mapper.Map<List<Models.Job>, List<Models.API.Job>>(source.ToList()),
source.PageNumber,
source.PageSize,
source.TotalItemCount));
在此示例中,我将一种对象类型的 X.PagedList 自定义集合类型映射到另一种对象类型的等效集合。 lamdba 表达式的第一个参数是您的源对象,第二个参数是您的
ResolutionContext
,您可以从中访问要映射的映射器实例。