c# - formember - automapper net core
¿Cómo usar mapper.Map dentro de MapperConfiguration de AutoMapper? (2)
Necesito asignar un objeto a otro usando AutoMapper. La pregunta difícil es ¿cómo puedo acceder a una instancia del asignador (instancia de IMapper) dentro de la configuración de mapeo o dentro de un convertidor de tipo personalizado?
El código a continuación no funciona, sin embargo, es un ejemplo de lo que me gustaría lograr. Observe el mapper.Map
un mapper.Map
llamadas y suponga que se definen las asignaciones Customer => CustomerDto
y 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)
})
);
La parte del cliente es:
var mapper = config.CreateMapper();
var orderDto = mapper.Map<Order, OrderDto>(order);
La versión simplificada de los objetos que quiero asignar es:
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; }
}
Como se ve en los códigos anteriores, según el valor de Order.Type
, el asignador debe asignar la propiedad Order.Customer
a diferentes objetivos. Como un objetivo ( DetailedCustomerDto
) se hereda del otro ( CustomerDto
), se vuelve un poco complicado.
Tenga en cuenta que el uso del método estático obsoleto y en desuso Mapper.Map NO es una opción .
Además de la gran respuesta de Evk, que me ayudó, si necesita realizar un mapeo dentro de un mapeo dentro de una configuración / perfil que requiere un constructor personalizado (es decir, el tipo no tiene un constructor predeterminado), lo siguiente funcionará en 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));
En este ejemplo, estoy asignando el tipo de colección personalizada X.PagedList de un tipo de objeto a una colección equivalente de otro tipo de objeto. El primer parámetro de la expresión lamdba es su objeto de origen, el segundo es su ResolutionContext
desde el cual puede acceder a una instancia del asignador desde la que asignar.
A partir de AutoMapper 5.1.1
Puede llegar al asignador usando otra sobrecarga de ResolveUsing
con cuatro parámetros, el cuarto de los cuales es ResolutionContext
( 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));
Antes de AutoMapper 5.1.1
Puede llegar al asignador utilizando otra sobrecarga de ResolveUsing
con dos parámetros, el primero de los cuales es 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));