Skip to content

Conversation

@maliming
Copy link
Member

@maliming maliming commented Aug 2, 2025

See Migrating from AutoMapper to Mapperly

If you can use Cursor, you can add all Profile class to context and let AI to change:

Refer to the class code below I provided and convert these content files from AutoMapper to Mapperly. 

Also, change the file name from  `XXXAutomapperProfile` to `XXXMappers`.

using System;
using AutoMapper;
using System.Linq;
using Volo.Abp.AutoMapper;

namespace Volo.Abp.Identity;

public class ExampleAutoMapper : Profile
{
    public AbpIdentityApplicationModuleAutoMapperProfile()
    {
        CreateMap<IdentityUser, IdentityUserDto>()
            .MapExtraProperties()
            .Ignore(x => x.IsLockedOut)
            .Ignore(x => x.SupportTwoFactor)
            .Ignore(x => x.RoleNames);

        CreateMap<IdentityUserClaim, IdentityUserClaimDto>();

        CreateMap<OrganizationUnit, OrganizationUnitDto>()
            .MapExtraProperties();

        CreateMap<OrganizationUnitRole, OrganizationUnitRoleDto>()
            .ReverseMap();

        CreateMap<IdentityRole, OrganizationUnitRoleDto>()
            .ForMember(dest => dest.RoleId, src => src.MapFrom(r => r.Id));

        CreateMap<IdentityUser, IdentityUserExportDto>()
            .ForMember(dest => dest.Active, src => src.MapFrom(r => r.IsActive ? "Yes" : "No"))
            .ForMember(dest => dest.EmailConfirmed, src => src.MapFrom(r => r.EmailConfirmed ? "Yes" : "No"))
            .ForMember(dest => dest.TwoFactorEnabled, src => src.MapFrom(r => r.TwoFactorEnabled ? "Yes" : "No"))
            .ForMember(dest => dest.AccountLookout, src => src.MapFrom(r => r.LockoutEnd != null && r.LockoutEnd > DateTime.UtcNow ? "Yes" : "No"))
            .Ignore(x => x.Roles);
    }
}


using System;
using System.Linq;
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;

namespace Volo.Abp.Identity;

[Mapper]
[MapExtraProperties]
public partial class IdentityUserToIdentityUserDtoMapper : MapperBase<IdentityUser, IdentityUserDto>
{
    [MapperIgnoreTarget(nameof(IdentityUserDto.IsLockedOut))]
    [MapperIgnoreTarget(nameof(IdentityUserDto.SupportTwoFactor))]
    [MapperIgnoreTarget(nameof(IdentityUserDto.RoleNames))]
    public override partial IdentityUserDto Map(IdentityUser source);

    [MapperIgnoreTarget(nameof(IdentityUserDto.IsLockedOut))]
    [MapperIgnoreTarget(nameof(IdentityUserDto.SupportTwoFactor))]
    [MapperIgnoreTarget(nameof(IdentityUserDto.RoleNames))]
    public override partial void Map(IdentityUser source, IdentityUserDto destination);
}

[Mapper]
public partial class IdentityUserClaimToIdentityUserClaimDtoMapper : MapperBase<IdentityUserClaim, IdentityUserClaimDto>
{
    public override partial IdentityUserClaimDto Map(IdentityUserClaim source);

    public override partial void Map(IdentityUserClaim source, IdentityUserClaimDto destination);
}

[Mapper]
[MapExtraProperties]
public partial class OrganizationUnitToOrganizationUnitDtoMapper : MapperBase<OrganizationUnit, OrganizationUnitDto>
{
    public override partial OrganizationUnitDto Map(OrganizationUnit source);
    public override partial void Map(OrganizationUnit source, OrganizationUnitDto destination);
}

[Mapper]
public partial class OrganizationUnitRoleToOrganizationUnitRoleDtoMapper : TwoWayMapperBase<OrganizationUnitRole, OrganizationUnitRoleDto>
{
    public override partial OrganizationUnitRoleDto Map(OrganizationUnitRole source);
    public override partial void Map(OrganizationUnitRole source, OrganizationUnitRoleDto destination);

    public override partial OrganizationUnitRole ReverseMap(OrganizationUnitRoleDto destination);
    public override partial void ReverseMap(OrganizationUnitRoleDto destination, OrganizationUnitRole source);
}

[Mapper]
[MapExtraProperties]
public partial class OrganizationUnitToOrganizationUnitWithDetailsDtoMapper : MapperBase<OrganizationUnit, OrganizationUnitWithDetailsDto>
{
    [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.Roles))]
    [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.UserCount))]
    public override partial OrganizationUnitWithDetailsDto Map(OrganizationUnit source);

    [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.Roles))]
    [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.UserCount))]
    public override partial void Map(OrganizationUnit source, OrganizationUnitWithDetailsDto destination);
}

[Mapper]
public partial class IdentityRoleToOrganizationUnitRoleDtoMapper : MapperBase<IdentityRole, OrganizationUnitRoleDto>
{
    [MapProperty(nameof(IdentityRole.Id), nameof(OrganizationUnitRoleDto.RoleId))]
    public override partial OrganizationUnitRoleDto Map(IdentityRole source);

    [MapProperty(nameof(IdentityRole.Id), nameof(OrganizationUnitRoleDto.RoleId))]
    public override partial void Map(IdentityRole source, OrganizationUnitRoleDto destination);
}

[Mapper]
public partial class IdentityUserToIdentityUserExportDtoMapper : MapperBase<IdentityUser, IdentityUserExportDto>
{
    [MapperIgnoreTarget(nameof(IdentityUserExportDto.Roles))]
    public override partial IdentityUserExportDto Map(IdentityUser source);

    [MapperIgnoreTarget(nameof(IdentityUserExportDto.Roles))]
    public override partial void Map(IdentityUser source, IdentityUserExportDto destination);

    public override void AfterMap(IdentityUser source, IdentityUserExportDto destination)
    {
        destination.Active = source.IsActive ? "Yes" : "No";
        destination.EmailConfirmed = source.EmailConfirmed ? "Yes" : "No";
        destination.TwoFactorEnabled = source.TwoFactorEnabled ? "Yes" : "No";
        destination.AccountLookout = source.LockoutEnd != null && source.LockoutEnd > DateTime.UtcNow ? "Yes" : "No";
    }
}

@maliming maliming added this to the 10.0-preview milestone Aug 2, 2025
@maliming maliming changed the title [Identity] Replace AutoMapper with Mapperly. [Identity & Account] Replace AutoMapper with Mapperly. Aug 3, 2025
@maliming maliming requested a review from EngincanV August 4, 2025 04:52
Base automatically changed from Mapperly-Map-Collection to dev August 4, 2025 07:16
EngincanV

This comment was marked as resolved.

@EngincanV EngincanV merged commit 6a8a5bc into dev Aug 4, 2025
3 checks passed
@EngincanV EngincanV deleted the Mapperly-maliming branch August 4, 2025 13:47
@jevonsflash
Copy link

At present, is there a compatible solution provided? Because I really don't want to rewrite a large number of types defined by AutoMapperProfile in the project, but inevitably these types require built-in type conversions like IdentityUser -> IdentityUserDto
image

@maliming
Copy link
Member Author

@jevonsflash
Copy link

I have read this article. The compatibility solution I'm say here is something can "bridge" Mapperly and AutoMapper injection method? like the Populate() method of Autofac.

You can continue to use AutoMapper.

See https://abp.io/docs/10.0/release-info/migration-guides/AutoMapper-To-Mapperly

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.

4 participants