mapperly icon indicating copy to clipboard operation
mapperly copied to clipboard

Use existing mapping rules from an "existing target object" map on a "new instance" map

Open mpickers opened this issue 1 year ago • 0 comments

When you have a mapping for creating a new instance of the target as well as setting an existing target object you have to duplicate the mapping information/rules as 2 separate maps are generated by Mapperly rather than using the same rules.

Example:

public class MyClass
{
   public int Id { get; set; }
   public string Name { get; set; }
}

public class MyClassDto
{
   public int Id { get; set; }
   public string TheName { get; set; }
}

public static partial class MyClassMapping
{
   [MapperRequiredMapping(RequiredMappingStrategy.Target)]                  // Same rules as ToExistingDto
   [MapProperty(nameof(MyClass.Name), nameof(MyClassDto.TheName))]          // Same rules as ToExistingDto
   public static partial MyClassDto ToMyClassDto(this MyClass o);

   [MapperRequiredMapping(RequiredMappingStrategy.Target)]
   [MapProperty(nameof(MyClass.Name), nameof(MyClassDto.TheName))]
   public static partial void ToExistingDto(this MyClass o, MyClassDto dto);
}

// Generated code

    public static partial class MyClassMapping
    {
        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.6.0.0")]
        public static partial global::MapperlyDebug.Entities.MyClassDto ToMyClassDto(this global::MapperlyDebug.Entities.MyClass o)
        {
            var target = new global::MapperlyDebug.Entities.MyClassDto();
            target.Id = o.Id;
            target.TheName = o.Name;
            return target;
        }

        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.6.0.0")]
        public static partial void ToExistingDto(this global::MapperlyDebug.Entities.MyClass o, global::MapperlyDebug.Entities.MyClassDto dto)
        {
            dto.Id = o.Id;
            dto.TheName = o.Name;
        }
    }

Describe the solution you'd like When there is a target type signature specified, use that as the main mapper and make the mapper that creates a new instance, use that mapping method.

Alternately if this needs to be explicit, have an attribute to specify the mapper method to use in the "new instance" map.

[Mapper]
public static partial class MyClassMapping
{
   public static partial MyClassDto ToMyClassDto(this MyClass o);

   [MapperRequiredMapping(RequiredMappingStrategy.Target)]
   [MapProperty(nameof(MyClass.Name), nameof(MyClassDto.TheName))]
   public static partial void ToExistingDto(this MyClass o, MyClassDto dto);
}

// OR

[Mapper]
public static partial class MyClassMapping
{
   [MapUsingCopyMethod] or something like [MapUsingRulesFromCopyMethod]
   public static partial MyClassDto ToMyClassDto(this MyClass o);

   [MapperRequiredMapping(RequiredMappingStrategy.Target)]
   [MapProperty(nameof(MyClass.Name), nameof(MyClassDto.TheName))]
   public static partial void ToExistingDto(this MyClass o, MyClassDto dto);
}

Expected generated code Either the use the rules from the other mapping definition which will result in the exact same output as above generated code OR use the existing object mapper in the "new object" map...

    public static partial class MyClassMapping
    {
        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.6.0.0")]
        public static partial global::MapperlyDebug.Entities.MyClassDto ToMyClassDto(this global::MapperlyDebug.Entities.MyClass o)
        {
            var target = new global::MapperlyDebug.Entities.MyClassDto();
            ToMyClassDto(o, target);
            return target;
        }

        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "3.6.0.0")]
        public static partial void ToExistingDto(this global::MapperlyDebug.Entities.MyClass o, global::MapperlyDebug.Entities.MyClassDto dto)
        {
            dto.Id = o.Id;
            dto.TheName = o.Name;
        }
    }

mpickers avatar May 22 '24 05:05 mpickers