I’ve encountered a similar issue.
Mapster correctly maps a direct property like: dest => dest.Amount, src => src.Amount.
However, it fails to map nested properties such as: dest => dest.InnerAmount, src => src.Inner.Amount
InnerAmount always ends up with the default value (NULL EUR).
Similar problem with PartnerCode.
bar.InnerPartnerCode.Value contains the type name instead of the expected value: "Tests.Tools.PartnerCode".
.Map(dest => dest.InnerPartnerCode, src => new PartnerCode(src.Inner.PartnerCode.Value, src.Inner.PartnerCode.IsForeigner))
.Map(dest => dest.InnerAmount, src => new Money(src.Inner.Amount.Amount, src.Inner.Amount.Currency))
I’m looking for a global solution, because I would prefer not to change all my individual mappings.
Has anyone experienced this or knows what might cause Mapster to behave differently for nested mappings?
[TestClass]
public class MapsterConverterTest
{
[TestMethod]
public async Task LoadTariffsTest()
{
// Arrange
var config = TypeAdapterConfig.GlobalSettings;
Register(config);
config.Default.ShallowCopyForSameType(true);
config.Default.MapToConstructor(true);
config.Default.IgnoreNullValues(true);
config.Default.MaxDepth(10);
config.Default.NameMatchingStrategy(NameMatchingStrategy.Flexible);
config.Default.AddDestinationTransform((string? s) => string.IsNullOrEmpty(s) ? null : s);
config.RequireExplicitMapping = false;
config.Compile();
Foo foo = new()
{
Amount = new(1, Currency.Usd),
PartnerCode = new("company", true),
Inner = new()
{
Amount = new(10, Currency.Eur),
Int = 100,
PartnerCode = new("Inner company", true)
}
};
// Act
var bar = foo.Adapt<Bar>(config);
// Assert
Assert.AreEqual(10m, bar.InnerAmount.Amount);
}
private void Register(TypeAdapterConfig config)
{
config.ForType<Foo, Bar>()
.Map(dest => dest.Amount, src => src.Amount)
.Map(dest => dest.InnerAmount, src => src.Inner.Amount)
.Map(dest => dest.PartnerCode, src => src.PartnerCode)
.Map(dest => dest.InnerPartnerCode, src => src.Inner.PartnerCode)
//.Map(dest => dest.InnerAmount, src => new Money(src.Inner.Amount, src.Inner.Amount.Currency))
.Map(dest => dest.InnerInt, src => src.Inner.Int);
config.NewConfig<PartnerCode, PartnerCode>()
.MapWith(src => src);
}
}
file class Foo
{
public required Money Amount { get; set; }
public PartnerCode PartnerCode { get; set; }
public required FooInner Inner { get; set; }
}
file class FooInner
{
public required Money Amount { get; set; }
public PartnerCode PartnerCode { get; set; }
public int Int { get; set; }
}
file class Bar
{
public required Money Amount { get; set; }
public required Money InnerAmount { get; set; }
public int InnerInt { get; set; }
public PartnerCode PartnerCode { get; set; }
public PartnerCode InnerPartnerCode { get; set; }
}
public struct PartnerCode(string? value, bool isForeigner)
{
public string? Value { get; set; } = value;
public bool IsForeigner { get; set; } = isForeigner;
}
public struct Money
{
public decimal? Amount { get; set; }
public Currency Currency { get; set; } = Currency.Ron;
public Money(decimal? amount, Currency currency = Currency.Eur)
{
Amount = amount;
Currency = currency;
}
}
.Map(dest => dest.InnerAmount, src => src.Inner.Amount)
Originally posted by @semi07 in #615