AutoMapper MapFrom 没有效果

AutoMapper MapFrom has no effect

已编辑:添加带有参数信息的构造函数。

我正在使用 AutoMapper 9.0 版和 .Net Core 2.1 以下单元测试应该更改 stockRecord.ClosePrice 的值,但如果存在第二个构造函数则不会。一旦注释掉第二个构造函数 closePrice 将具有正确的值 100.

股票记录Class

[DynamoDBTable("StockRecord")]
public class StockRecord
{
    [DynamoDBHashKey]
    public string TickerSymbol { get; set; }

    [DynamoDBRangeKey]
    public DateTime TradingDay { get; private set; }

    public float OpenPrice { get; private set; }
    public float ClosePrice { get; private set; }
    public float DayHighestPrice { get; private set; }
    public float DayLowestPrice { get; private set; }

    public StockRecord() {}

    // add this constructor below will make the unit test below fail, ClosePrice will stay value of 20
    // Once Comment out this constructor, unit test will pass, ClosePrice value will change to 100
    public StockRecord(string tickerSymbol, DateTime tradingDay, float openPrice, float closePrice, float dayHighestPrice, float dayLowestPrice)
    {
        TickerSymbol = tickerSymbol;
        TradingDay = tradingDay;
        OpenPrice = openPrice;
        ClosePrice = closePrice;
        DayHighestPrice = dayHighestPrice;
        DayLowestPrice = dayLowestPrice;
    }       
}

StockRecordDto Class

public class StockRecordDto
{
    public string TickerSymbol { get; set; }
    public DateTime TradingDay { get; set; }
    public float OpenPrice { get; set; }
    public float ClosePrice { get; set; }
    public float DayHighestPrice { get; set; }
    public float DayLowestPrice { get; set; }
}

单元测试

[Fact]
public void Test1()
{
    var configuration = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<StockRecord, StockRecordDto>()
        .ForMember(dst => dst.ClosePrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 300 : 400))
        .ReverseMap()
        .ForMember(dst => dst.ClosePrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 100 : 200));
    });
    configuration.AssertConfigurationIsValid();

    var mapper = configuration.CreateMapper();

    var stockRecordDto = new StockRecordDto
    {
        TickerSymbol = "ticker 01",
        TradingDay = DateTime.Now,
        OpenPrice = 10,
        ClosePrice = 20,
        DayHighestPrice = 30,
        DayLowestPrice = 5
    };

    StockRecord stockRecord = mapper.Map<StockRecord>(stockRecordDto);
    Assert.Equal(100, stockRecord.ClosePrice);
}

根据 autoMapper 的文档,`stockRecord.ClosePrice 应该更改为 100。但它仍然是 20。 我花了整个下午,但仍然无法弄清楚。 我可以用工厂方法替换构造函数,但我仍然不明白为什么带参数的构造函数会出现问题。

如果这是一个错误,我将 post 在 AutoMapper 的 github 上提出一个问题。

谢谢。

如果您想更改 DayLowestPrice,则在您的映射中使用 DayLowestPrice 作为目标字段而不是 ClosePrice:

cfg.CreateMap<StockRecord, StockRecordDto>()
        .ForMember(dst => dst.DayLowestPrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 300 : 400))
        .ReverseMap()
        .ForMember(dst => dst.DayLowestPrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 100 : 200));

编辑:

由于您有一个带参数的构造函数,它被用来创建 StockRecord。因此,您可以通过 FromCtorParam:

为构造函数成员显式指定映射
cfg.CreateMap<StockRecord, StockRecordDto>()
  .ForMember(dst => dst.DayLowestPrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 300 : 400))
  .ReverseMap()
  .ForCtorParam("closePrice", op => op.MapFrom(src => src.ClosePrice > 0 ? 100 : 200));

详细说明您的对象需要如何构建。您可以在 github.

上找到有关其行为为何如此的更多信息

编辑2:

您也可以使用 ConstructUsing,但在这种情况下,您应该将属性设置为只读(从属性中删除 private set;)并指定所有构造函数参数。在这种情况下,您可以避免硬编码构造函数参数名称。

public class StockRecord
{
       ***

    public float ClosePrice { get; }

       ***
}

cfg.CreateMap<StockRecordDto, StockRecord>()
  .ConstructUsing(s => new StockRecord(s.TickerSymbol, s.TradingDay, s.OpenPrice, s.ClosePrice > 0 ? 100 : 200, s.DayHighestPrice, s.DayLowestPrice));