使用密钥将列表映射到Automapper中的现有列表

Automapper可以轻松处理将一个对象类型列表映射到另一个不同对象类型的列表,但是是否可以使用ID作为键将其映射到现有列表?

我没有找到比以下更好的方法。

这是源和目的地。

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; } } 

定义转换器(您应该将List <>更改为您正在使用的任何类型)。

 public class CollectionConverter: ITypeConverter, List> { public List Convert(ResolutionContext context) { var destinationCollection = (List)context.DestinationValue; if(destinationCollection == null) destinationCollection = new List(); var sourceCollection = (List)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(source)); } return destinationCollection; } } 

这是实际的映射配置和示例。

 Mapper.CreateMap(); Mapper.CreateMap,List>().ConvertUsing(new CollectionConverter()); var sourceCollection = new List { new Source{ Id = 1, Foo = "Match"}, new Source{ Id = 2, Foo = "DoesNotMatchWithDestination"} }; var destinationCollection = new List { new Destination{ Id = 1, Foo = "Match"}, new Destination{ Id = 3, Foo = "DoeNotMatchWithSource"} }; var mergedCollection = Mapper.Map(sourceCollection, destinationCollection); 

你应该得到以下结果。

映射结果

我发现这篇文章非常有用,因此我想我会反馈我的通用版本的类型转换器,您可以使用它来从每个对象中选择要匹配的属性。

使用它你需要做的就是:

 // Example of usage Mapper.CreateMap(); var converter = CollectionConverterWithIdentityMatching.Instance(model => model.Id, user => user.Id); Mapper.CreateMap, List>().ConvertUsing(converter); //The actual converter public class CollectionConverterWithIdentityMatching : ITypeConverter, List> where TDestination : class { private readonly Func sourcePrimaryKeyExpression; private readonly Func destinationPrimaryKeyExpression; private CollectionConverterWithIdentityMatching(Expression> sourcePrimaryKey, Expression> destinationPrimaryKey) { this.sourcePrimaryKeyExpression = sourcePrimaryKey.Compile(); this.destinationPrimaryKeyExpression = destinationPrimaryKey.Compile(); } public static CollectionConverterWithIdentityMatching Instance(Expression> sourcePrimaryKey, Expression> destinationPrimaryKey) { return new CollectionConverterWithIdentityMatching( sourcePrimaryKey, destinationPrimaryKey); } public List Convert(ResolutionContext context) { var destinationCollection = (List)context.DestinationValue ?? new List(); var sourceCollection = (List)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(source)); } } return destinationCollection; } private string GetPrimaryKey(object entity, Func expression) { var tempId = expression.Invoke((TObject)entity); var id = System.Convert.ToString(tempId); return id; } }