Automapper 将多个可选属性映射到列表

Automapper Map multiple optional properties to list

我有一个 class OrderLineRequest,我想将其映射到带有条形码列表的 OrderLine class。仅当包含值时,才需要将属性 Barcode1、2、3 映射到 Barcodes。 Barcode1 始终填写,Barcode2 和 Barcode3 可选。我创建了一个映射,但这在列表中总是给我 3 个条形码。如果 Barcode1 或 2 是空字符串,我不想将它们添加到列表中。我该怎么做?

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

为什么你总是创建那三个条形码? 我建议你为谓词创建一个函数 接受 OrderLineRequest 和 returns 您的 List 并处理函数内的创建。像这样:

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

然后你可以像这样使用它:

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

如果您使用的是 Automapper,将源中的三个特定属性添加到目标列表中的步骤无法使用简单的函数来完成。你必须告诉 Automapper 如何完成它。

您可以在初始映射期间告诉它忽略这些属性,然后在映射完成后将项目添加到目标列表。

为简洁起见,这仅包括那些属性:

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

可以说,这为您编写自己的扩展而不是使用 Automapper 提供了理由。当映射很简单时它很方便,但如果不是那么使用它可能会比它的价值更麻烦。这是一个偏好问题。

创建一个包含三个属性的数组。一旦它在数组中,您可以使用 Where 删除空值并使用 Select 实例化 EanCode 实例。一旦数据状态良好,请调用 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()
    )
);