Skip to content

Conversation

@maliming
Copy link
Member

@maliming maliming commented Jul 9, 2025

Description

Resolves #23243


We need to create a mapper that inherits from MapperBase<TSource, TDestination> for each DTO class, and then you can use various features of Mapperly in this mapper class. You can also override the BeforeMap and AfterMap methods to perform some actions.

The MyClassMapper will be added to the DI system. You can also inject services in this mapper class.

Mapperly will generate the implementation Map methods code during the build process.

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

    public string Name { get; set; }
}

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

    public string Name { get; set; }
}

[Mapper]
public partial class MyClassMapper : MapperBase<MyClass, MyClassDto>
{
    public override partial MyClassDto Map(MyClass source);

    public override partial void Map(MyClass source, MyClassDto destination);

    public override void BeforeMap(MyClass source)
    {
        //source.Name = "BeforeMap " + source.Name;
    }

    public override void AfterMap(MyClass source, MyClassDto destination)
    {
        //destination.Name = source.Name + " AfterMap";
    }
}
// <auto-generated />
#nullable enable
namespace Volo.Abp.Mapperly
{
    public partial class MyClassMapper
    {
        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "4.2.1.0")]
        [return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(source))]
        public override partial global::Volo.Abp.Mapperly.MyClassDto? Map(global::Volo.Abp.Mapperly.MyClass? source)
        {
            if (source == null)
                return default;
            var target = new global::Volo.Abp.Mapperly.MyClassDto();
            target.Id = source.Id;
            target.Name = source.Name;
            return target;
        }

        [global::System.CodeDom.Compiler.GeneratedCode("Riok.Mapperly", "4.2.1.0")]
        public override partial void Map(global::Volo.Abp.Mapperly.MyClass? source, global::Volo.Abp.Mapperly.MyClassDto? destination)
        {
            if (source == null || destination == null)
                return;
            destination.Id = source.Id;
            destination.Name = source.Name;
        }
    }
}

If you want the mapper to support reverse mapping, you can use TwoWayMapperBase as the base class.

[Mapper]
public partial class MyClassMapper : TwoWayMapperBase<MyClass, MyClassDto>
{
    public override partial MyClassDto Map(MyClass source);

    public override partial void Map(MyClass source, MyClassDto destination);

    public override partial MyClass ReverseMap(MyClassDto destination);

    public override partial void ReverseMap(MyClassDto destination, MyClass source);

    public override void BeforeReverseMap(MyClassDto destination)
    {
        //destination.Name = "BeforeReverseMap " + destination.Name;
    }

    public override void AfterReverseMap(MyClassDto destination, MyClass source)
    {
        //source.Name = destination.Name + " AfterReverseMap";
    }
}

@maliming maliming added this to the 10.0-preview milestone Jul 9, 2025
@maliming maliming marked this pull request as ready for review July 9, 2025 13:07
@rqx110
Copy link
Contributor

rqx110 commented Jul 10, 2025

every mapper class we need write:

public override partial MyClassDto Map(MyClass source);

public override partial void Map(MyClass source, MyClassDto destination);

Is there a way to automate these template codes?

@maliming
Copy link
Member Author

Is there a way to automate these template codes?

I didn't find it.

@maliming maliming requested a review from hikalkan July 11, 2025 00:53
@rqx110
Copy link
Contributor

rqx110 commented Jul 12, 2025

Suggestion: Rename AbpReverseMapperlyMapper to AbpTwoWayMapperlyMapper, and the order of T can same with AbpMapperlyMapper(MyClass, MyClassDto). AbpReverseMapperlyMapper contains not only reverse mapping but also forward mapping.

@maliming
Copy link
Member Author

@rlopes4dev
Copy link

Can the generated class have access to the IServiceProvider from the base class? Some custom mappers can required the injection of services.

@maliming
Copy link
Member Author

Can the generated class have access to the IServiceProvider from the base class? Some custom mappers can required the injection of services.

No problem, you can see this mapper class: https://github.com/abpframework/abp/blob/9e0d0413d0cf6c23d7fb4db17a9e8183bcb88d35/framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperly_Dependency_Injection_Tests.cs

@hikalkan
Copy link
Member

hikalkan commented Jul 21, 2025

Renaming AbpReverseMapperlyMapperBase to AbpTwoWayMapperlyMapperBase seems reasonable to me.

Actually even MapperBase and TwoWayMapperBase are enough since they will be located in Volo.Abp.Mapperly namespace.

@maliming
Copy link
Member Author

Renaming AbpReverseMapperlyMapperBase to AbpTwoWayMapperlyMapperBase seems reasonable to me.

Actually even MapperBase and TwoWayMapperBase are enough since they will be located in Volo.Abp.Mapperly namespace.

Changed.

@hikalkan hikalkan merged commit ef28115 into dev Jul 31, 2025
2 of 3 checks passed
@hikalkan hikalkan deleted the Mapperly branch July 31, 2025 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch to another object mapping library

5 participants