Merge two collections with Automapper by condition

2019-07-08 02:36发布

问题:

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?

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


回答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



标签: c# AutoMapper