'Merge two collections with Automapper by condition
There are two types:
1) DTO type:
[DataContract]
public sealed class OrderDetailDto
{
[DataMember]
public Guid MergeId { get; set; }
[DataMember]
public int Id { get; set; }
[DataMember]
public string PostionName { get; set; }
[DataMember]
public decimal Quantity { get; set; }
[DataMember]
public byte[] Version { get; set; }
}
2) corresponding domain type:
public sealed class OrderDetail
{
public Guid MergeId { get; set; }
public int Id { get; set; }
public string PostionName { get; set; }
public decimal Quantity { get; set; }
public byte[] Version { get; set; }
}
and two collections: Collection<OrderDetail> and Collection<OrderDetailDto>.
Collection<OrderDetailDto> has data changes, that was made somewhere. Now I want to apply these changes to Collection<OrderDetail>, using Automapper.
For simplicity, let's think, that items count in these collections are equal, but the order of items may differ.
To map collection items correctly, I want to use MergeId property. I need something like this:
Mapper.CreateMap<Collection<OrderDetailDto>, Collection<OrderDetail>>()
.MappingExpression((dto, do) => dto.MergeId == do.MergeId);
Is this possible to do with Automapper?
Solution 1:[1]
I have not found better solution than using custom converter like below.
public class Converter : ITypeConverter<Collection<OrderDetailDto>, Collection<OrderDetail>>
{
public Collection<OrderDetail> Convert(ResolutionContext context)
{
var destCollection = (Collection<OrderDetail>) context.DestinationValue;
var sourceCollection = (Collection<OrderDetailDto>)context.SourceValue;
foreach (var source in sourceCollection)
{
var dest = destCollection.SingleOrDefault(d => d.MergeId == source.MergeId);
Mapper.Map(source, dest);
}
return destCollection;
}
}
Solution 2:[2]
Yet another solution could simply to combine a linq query + automapper.
the basic concept is show here :
var res = from a in orderDetails
join b in orderDetailsDto on a.MergeId equals b.MergeId
where a.Update == true // determine update selector here
select new { a, b };
res.Each(item => Mapper.Map<OrderDetail, OrderDetailDto>(item.a, item.b));
It is also easy to extract a generic extension method (based on the join extension method) for all merges
Solution 3:[3]
i have modified k0stya's answer in a genetic way
public class ListToListConverter<TEntity,TDto> : ITypeConverter<Collection<TDto>, Collection<TEntity>>
where TEntity : class
where TDto:BaseDto
{
public Collection<TEntity> Convert(Collection<TDto> dtos, Collection<TEntity> entities,ResolutionContext context)
{
var destCollection=new Collection<TEntity>();
foreach (var source in dtos)
{
var dest = entities.SingleOrDefault(d => ((dynamic)d).Id == source.Id);
context.Mapper.Map(source, dest);
destCollection.Add(dest);
}
return destCollection;
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | k0stya |
| Solution 2 | Cybermaxs |
| Solution 3 | hershy kohn |
