c# - mvc - Pasar objetos al mapeo de AutoMapper
mapper initialize (4)
AutoMapper maneja este escenario de par clave-valor fuera de la caja.
Mapper.CreateMap<Source, Dest>()
.ForMember(d => d.Foo, opt => opt.ResolveUsing(res => res.Context.Options.Items["Foo"]));
Luego en el tiempo de ejecución:
Mapper.Map<Source, Dest>(src, opt => opt.Items["Foo"] = "Bar");
Un poco detallado para profundizar en los elementos de contexto, pero hay que ir.
Estoy trabajando con AutoMapper y algunos de los valores de la entidad a la que se asigna son variables en mi método actual. He intentado buscarlo en Google, pero sin éxito. ¿Puedo pasar un conjunto de pares de KeyValue o un objeto o algo a mi asignación para que use esos valores?
Muestra de modificación de post mapeo
//comment variable is a Comment class instance
var imageComment = AutoMapper.Mapper.Map<Data.ImageComment>(comment);
//I want to pass in imageId so I dont have to manually add it after the mapping
imageComment.ImageId = imageId;
Los objetos se pueden pasar al resolutor con la opción Diccionario de Items
. La API estándar para hacer esto es bastante detallada (como se ve en la respuesta aceptada) pero se puede simplificar muy bien usando algunos métodos de extensión:
/// <summary>
/// Map using a resolve function that is passed the Items dictionary from mapping context
/// </summary>
public static void ResolveWithContext<TSource, TDest, TMember, TResult>(
this IMemberConfigurationExpression<TSource, TDest, TMember> memberOptions,
Func<TSource, IDictionary<string, object>, TDest, TMember, TResult> resolver
) {
memberOptions.ResolveUsing((src, dst, member, context) => resolver.Invoke(src, context.Items, dst, member));
}
public static TDest MapWithContext<TSource, TDest>(this IMapper mapper, TSource source, IDictionary<string, object> context, Action<IMappingOperationOptions<TSource, TDest>> optAction = null) {
return mapper.Map<TSource, TDest>(source, opts => {
foreach(var kv in context) opts.Items.Add(kv);
optAction?.Invoke(opts);
});
}
Que se puede usar así:
// Define mapping configuration
Mapper.CreateMap<Comment, ImageComment>()
.ForMember(
d => d.ImageId,
opt => opt.ResolveWithContext(src, items, dst, member) => items["ImageId"])
);
// Execute mapping
var context = new Dictionary<string, object> { { "ImageId", ImageId } };
return mapper.MapWithContext<TSource, TDest>(source, context);
Si tiene un objeto que comúnmente necesita pasar a los solucionadores de asignadores (por ejemplo, el usuario actual), puede ir un paso más allá y definir extensiones más especializadas:
public static readonly string USER_CONTEXT_KEY = "USER";
/// <summary>
/// Map using a resolve function that is passed a user from the
/// Items dictionary in the mapping context
/// </summary>
public static void ResolveWithUser<TSource, TDest, TMember, TResult>(
this IMemberConfigurationExpression<TSource, TDest, TMember> memberOptions,
Func<TSource, User, TResult> resolver
) {
memberOptions.ResolveWithContext((src, items, dst, member) =>
resolver.Invoke(src, items[USER_CONTEXT_KEY] as User));
}
/// <summary>
/// Execute a mapping from the source object to a new destination
/// object, with the provided user in the context.
/// </summary>
public static TDest MapForUser<TSource, TDest>(
this IMapper mapper,
TSource source,
User user,
Action<IMappingOperationOptions<TSource, TDest>> optAction = null
) {
var context = new Dictionary<string, object> { { USER_CONTEXT_KEY, user } };
return mapper.MapWithContext(source, context, optAction);
}
Que se puede utilizar como:
// Create mapping configuration
Mapper.CreateMap<Source, Dest>()
.ForMember(d => d.Foo, opt => opt.ResolveWithUser((src, user) src.Foo(user));
// Execute mapping
return mapper.MapWithUser(source, user);
Para Automapper 6.0.2:
Perfil:
public class CoreProfile : Profile
{
public CoreProfile()
{
CreateMap<Source, Dest>()
.ForMember(d => d.Foo,
opt => opt.ResolveUsing(
(src, dst, arg3, context) => context.Options.Items["Foo"]
)
);
}
}
Cartografía:
var result = Mapper.Map<PlanResult>(aa, opt => {
opt.Items["Foo"] = 2;
opt.Items["OtherFoo"] = 1000;
});
Supongamos que tienes estos dos objetos:
public class ObjectA {
public string Property1 { get; set; }
public int Property2 { get; set; }
}
public class ObjectB {
public string Property1 { get; set; }
public int Property2 { get; set; }
}
Y desea copiar un objeto existente de tipo ObjectA
en un nuevo objeto de tipo ObjectB
, utilizando AutoMapper tiene que hacer esto:
var objectA = new ObjectA { Property1 = "Hello, World!", Property2 = 1 }
var objectB = new ObjectB();
// Copy data from a to b
AutoMapper.Mapper
.CreateMap<ObjectA, ObjectB>()
.BeforeMap((source, dest) => { dest.ImageId = imageId });
AutoMapper.Mapper.Map(objectA, objectB); // source, destination;
// Or:
var objectB = AutoMapper.Mapper.Map<ObjectB>(objectA);