简体   繁体   中英

Automapper Map multiple optional properties to list

I have a class OrderLineRequest that I want to map to an OrderLine class with a list of barcodes. The properties Barcode1,2,3 needs to be mapped to Barcodes only if the contain a value. Barcode1 is always filled, Barcode2 and Barcode3 are optional. I have created a mapping but this gives me always 3 barcodes in the list. If Barcode1 or 2 is an empty string i don't want to add them to the list. How can i do this?

public class OrderLineRequest
{
    public string OrderLineId { get; set; }
    public string Barcode1 { get; set; }
    public string Barcode2 { get; set; }
    public string Barcode3 { get; set; }
    public int Quantity { get; set; }
}

public class OrderLine
{
    public int Id { get;set;}
    public int OrderId { get;set;}
    public string OrderLineNumber { get; set; }
    public int Qty { get; set; }
    public List<Barcode> Barcodes { get;set;}
}

public class Barcode
{
    public int Id { get;set;}
    public int OrderLineId { get;set;}
    public string Code { get;set;}
}

CreateMap<OrderLineRequest, OrderLine>()
            .ForMember(b => b.Id, e => e.Ignore())
            .ForMember(d => d.OrderId, p => p.Ignore())
            .ForMember(d => d.OrderLineNumber, p => p.MapFrom(s => s.OrderLineId))
            .ForMember(d => d.Qty, p => p.MapFrom(s => s.Quantity))
            .ForMember(d => d.BarCodes, p => p.MapFrom(s => new List<EanCode>() { new EanCode(){Code = s.Barcode1}, new EanCode() { Code = s.Barcode2 }, new EanCode() { Code = s.Barcode3 } }));

Why are you always creating those three barcodes? I would suggest you to create a function for the predicate that accepts OrderLineRequest and returns your List and handle the creation within the function. Like that:

private List<EanCode> Foo(OrderLineRequest orderLineRequest)  
{
    var result = new List<EanCode>();
    if(!string.IsNullOrEmpty(orderLineRequest.Barcode1) 
    result.Add(new EanCode {Code = orderLineRequest.Barcode1});
    //... 
    return result; 
}    

And then you could use it like:

.ForMember(d => d.BarCodes, p => p.MapFrom(s =>  Foo(s)));

If you're using Automapper, the step of adding three specific properties from the source to a list in the destination can't be accomplished with a simple function. You have to tell Automapper how to accomplish it.

You can do that by telling it to ignore those properties during the initial mapping, and then add items to the destination list after that mapping is complete.

For brevity this includes only those properties:

var configuration = new MapperConfiguration(
     cfg => cfg.CreateMap<OrderLineRequest, OrderLine>()
        .ForMember(d => d.Barcodes, opt => opt.Ignore())
        .ForSourceMember(s => s.Barcode1, opt => opt.DoNotValidate())
        .ForSourceMember(s => s.Barcode2, opt => opt.DoNotValidate())
        .ForSourceMember(s => s.Barcode3, opt => opt.DoNotValidate())
        .AfterMap((source, destination) =>
        {
            destination.Barcodes = new List<Barcode>
            {
                new Barcode { Code = source.Barcode1 }
            };
            if (source.Barcode2 != null)
                destination.Barcodes.Add(new Barcode { Code = source.Barcode2 });
            if (source.Barcode3 != null)
                destination.Barcodes.Add(new Barcode { Code = source.Barcode3 });
        }));

It could be said that this makes a case for just writing your own extension instead of using Automapper. It's convenient when the mapping is simple, but if it's not then using it could arguably be more trouble than it's worth. That's a matter of preference.

Create an array of the three properties. Once it's in an array, you can use Where to remove the nulls and Select to instantiate the EanCode instances. Once the data are in good shape, call ToList() .

.ForMember
(
    d => d.BarCodes, 
    p => p.MapFrom
    (
        s => 
        (new [] { s.BarCode1, s.BarCode2, s.BarCode3 })
        .Where( x => x != null)
        .Select( x => new EanCode { Code = x } )
        .ToList()
    )
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM