Describe the bug
When using nested mappers within a mapper that has an existing target object mapping method, the calls to the nested mapper do not use the nested mapper's existing target object mapper. If the nested mapper has an existing target object mapping method and the calling mapper's object has a non-null value for the nested object, it should use the nested mapper's existing target object mapping method.
Note: this is important to fix so that the tracked entity is changed when using EF Core rather than creating a new entity
Declaration code
using Riok.Mapperly.Abstractions;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public sealed record HouseDto
{
public int Id { get; init; }
public required int NumWindows { get; init; }
public DoorDto? Door { get; init; }
}
public sealed record DoorDto
{
public int Id { get; init; }
public required bool IsWood { get; init; }
}
public sealed class HouseEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; init; }
public required int NumWindows { get; set; }
[ForeignKey(nameof(Door))]
public int? DoorId { get; private set; }
public DoorEntity? Door { get; set; }
}
public sealed class DoorEntity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; init; }
public required bool IsWood { get; set; }
}
[Mapper]
public sealed partial class HouseMapper
{
[UseMapper]
private readonly DoorMapper _doorMapper;
public HouseMapper(DoorMapper doorMapper)
{
_doorMapper = doorMapper;
}
public partial HouseEntity DtoToEntity(HouseDto dto);
public partial void DtoToEntity(HouseDto dto, HouseEntity entity);
}
[Mapper]
public sealed partial class DoorMapper
{
public partial DoorEntity DtoToEntity(DoorDto dto);
public partial void DtoToEntity(DoorDto dto, DoorEntity entity);
}
Actual relevant generated code
// <auto-generated />
#nullable enable
public sealed partial class HouseMapper
{
[global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.6.0.0")]
public partial global::HouseEntity DtoToEntity(global::HouseDto dto)
{
var target = new global::HouseEntity()
{
Id = dto.Id,
NumWindows = dto.NumWindows,
};
if (dto.Door != null)
{
target.Door = _doorMapper.DtoToEntity(dto.Door);
}
else
{
target.Door = null;
}
return target;
}
[global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.6.0.0")]
public partial void DtoToEntity(global::HouseDto dto, global::HouseEntity entity)
{
if (dto.Door != null)
{
entity.Door = _doorMapper.DtoToEntity(dto.Door);
}
else
{
entity.Door = null;
}
entity.NumWindows = dto.NumWindows;
}
}
Expected relevant generated code
// <auto-generated />
#nullable enable
public sealed partial class HouseMapper
{
...
public partial void DtoToEntity(global::HouseDto dto, global::HouseEntity entity)
{
- if (dto.Door != null)
+ if (dto.Door != null && entity.Door != null)
+ {
+ _doorMapper.DtoToEntity(dto.Door, entity.Door);
+ }
+ else if (dto.Door != null)
{
entity.Door = _doorMapper.DtoToEntity(dto.Door);
}
else
{
entity.Door = null;
}
entity.NumWindows = dto.NumWindows;
}
}
Environment:
- Mapperly Version: 3.6.0
- Nullable reference types: enabled
- .NET Version: 8.0.2
- Target Framework: .net8.0
- Compiler Version: 4.9.0-3.24121.1 (a98c90d5)
- C# Language Version: 12.0
- IDE: Visual Studio 2022
- OS: Windows 10
Additional Info
It seems like this problem also exists when you don't specify the nested object's mapper. The generated code for mapping the nested object never uses the existing nested object on the target object. Instead, it always creates a new nested object. This should also be fixed
Describe the bug
When using nested mappers within a mapper that has an existing target object mapping method, the calls to the nested mapper do not use the nested mapper's existing target object mapper. If the nested mapper has an existing target object mapping method and the calling mapper's object has a non-null value for the nested object, it should use the nested mapper's existing target object mapping method.
Note: this is important to fix so that the tracked entity is changed when using EF Core rather than creating a new entity
Declaration code
Actual relevant generated code
Expected relevant generated code
Environment:
Additional Info
It seems like this problem also exists when you don't specify the nested object's mapper. The generated code for mapping the nested object never uses the existing nested object on the target object. Instead, it always creates a new nested object. This should also be fixed