Automapper gestisce facilmente la mappatura di un elenco di tipi di oggetti in un altro elenco di tipi di oggetti diversi, ma è possibile averlo mappare a un elenco esistente utilizzando un ID come chiave?Mappa elenco all'elenco esistente in Automapper utilizzando una chiave
5
A
risposta
7
Non ho trovato il modo migliore rispetto al seguente.
Qui sono la fonte e la destinazione.
public class Source
{
public int Id { get; set; }
public string Foo { get; set; }
}
public class Destination
{
public int Id { get; set; }
public string Foo { get; set; }
}
Definire convertitore (Si dovrebbe cambiare Lista <> a qualsiasi tipo che si sta utilizzando).
public class CollectionConverter: ITypeConverter<List<Source>, List<Destination>>
{
public List<Destination> Convert(ResolutionContext context)
{
var destinationCollection = (List<Destination>)context.DestinationValue;
if(destinationCollection == null)
destinationCollection = new List<Destination>();
var sourceCollection = (List<Source>)context.SourceValue;
foreach(var source in sourceCollection)
{
Destination matchedDestination = null;
foreach(var destination in destinationCollection)
{
if(destination.Id == source.Id)
{
Mapper.Map(source, destination);
matchedDestination = destination;
break;
}
}
if(matchedDestination == null)
destinationCollection.Add(Mapper.Map<Destination>(source));
}
return destinationCollection;
}
}
E qui è la configurazione di mappatura effettiva ed esempio.
Mapper.CreateMap<Source,Destination>();
Mapper.CreateMap<List<Source>,List<Destination>>().ConvertUsing(new CollectionConverter());
var sourceCollection = new List<Source>
{
new Source{ Id = 1, Foo = "Match"},
new Source{ Id = 2, Foo = "DoesNotMatchWithDestination"}
};
var destinationCollection = new List<Destination>
{
new Destination{ Id = 1, Foo = "Match"},
new Destination{ Id = 3, Foo = "DoeNotMatchWithSource"}
};
var mergedCollection = Mapper.Map(sourceCollection, destinationCollection);
Si dovrebbe ottenere il seguente risultato.
1
Ho trovato questo articolo molto utile e come tale ho pensato di feed back nella mia versione generica del convertitore tipo che è possibile utilizzare per selezionare la proprietà in modo che corrisponda a da ogni oggetto.
Con esso tutto quello che dovete fare è:
// Example of usage
Mapper.CreateMap<UserModel, User>();
var converter = CollectionConverterWithIdentityMatching<UserModel, User>.Instance(model => model.Id, user => user.Id);
Mapper.CreateMap<List<UserModel>, List<User>>().ConvertUsing(converter);
//The actual converter
public class CollectionConverterWithIdentityMatching<TSource, TDestination> :
ITypeConverter<List<TSource>, List<TDestination>> where TDestination : class
{
private readonly Func<TSource, object> sourcePrimaryKeyExpression;
private readonly Func<TDestination, object> destinationPrimaryKeyExpression;
private CollectionConverterWithIdentityMatching(Expression<Func<TSource, object>> sourcePrimaryKey, Expression<Func<TDestination, object>> destinationPrimaryKey)
{
this.sourcePrimaryKeyExpression = sourcePrimaryKey.Compile();
this.destinationPrimaryKeyExpression = destinationPrimaryKey.Compile();
}
public static CollectionConverterWithIdentityMatching<TSource, TDestination>
Instance(Expression<Func<TSource, object>> sourcePrimaryKey, Expression<Func<TDestination, object>> destinationPrimaryKey)
{
return new CollectionConverterWithIdentityMatching<TSource, TDestination>(
sourcePrimaryKey, destinationPrimaryKey);
}
public List<TDestination> Convert(ResolutionContext context)
{
var destinationCollection = (List<TDestination>)context.DestinationValue ?? new List<TDestination>();
var sourceCollection = (List<TSource>)context.SourceValue;
foreach (var source in sourceCollection)
{
TDestination matchedDestination = default(TDestination);
foreach (var destination in destinationCollection)
{
var sourcePrimaryKey = GetPrimaryKey(source, this.sourcePrimaryKeyExpression);
var destinationPrimaryKey = GetPrimaryKey(destination, this.destinationPrimaryKeyExpression);
if (string.Equals(sourcePrimaryKey, destinationPrimaryKey, StringComparison.OrdinalIgnoreCase))
{
Mapper.Map(source, destination);
matchedDestination = destination;
break;
}
}
if (matchedDestination == null)
{
destinationCollection.Add(Mapper.Map<TDestination>(source));
}
}
return destinationCollection;
}
private string GetPrimaryKey<TObject>(object entity, Func<TObject, object> expression)
{
var tempId = expression.Invoke((TObject)entity);
var id = System.Convert.ToString(tempId);
return id;
}
}