AutoMapper MapFrom не имеет никакого эффекта - PullRequest
1 голос
/ 15 октября 2019

Отредактировано: чтобы добавить конструктор с информацией о параметрах.

Я использую AutoMapper версии 9.0 и .Net Core 2.1 Следующий модульный тест должен изменить значение stockRecord.ClosePrice, но это не так, если второй конструкторнастоящее. После комментария второй конструктор closePrice будет иметь правильное значение 100.

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

Unit Test

[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. Я потратил весь день на это, но все еще не мог понять это. Я мог бы заменить конструктор фабричным методом, но я до сих пор не понимаю, почему конструктор с параметрами будет причиной проблемы.

Если это ошибка, я опубликую проблему на github AutoMapper.

Спасибо.

1 Ответ

3 голосов
/ 15 октября 2019

Если вы хотите изменить 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 .

Edit2 :

Вы также можете использовать 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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...