ABP AutoMapper与自定义Mapping

对象映射

在工作中,需要将相似的对象映射到另一个对象,这样我们来看一个最繁琐的映射方式
例:
public class UserAppService : ApplicationService
{
    private readonly IRepository<User> _userRepository;

    public UserAppService(IRepository<User> userRepository)
    {
        _userRepository = userRepository;
    }

    public void CreateUser(CreateUserInput input)
    {
        var user = new User
        {
            Name = input.Name,
            Surname = input.Surname,
            EmailAddress = input.EmailAddress,
            Password = input.Password
        };

        _userRepository.Insert(user);
    }
}

通过 new 一个新的实体去赋值并保存数据,User 实体在现实的应用程序中会有更多的属性,这样的手动创建它会变得乏味且容易出错。当我们想要向 User 和 CreateUserInput 添加新属性时,我们还必须更改映射代码。

上个例子繁琐,我们做出改进

我们可以使用一个库来自动处理我们的映射。 AutoMapper是对象到对象映射的最佳库之一。ASP.NET Boilerplate 定义了一个IObjectMapper 接口来抽象它,然后使用Abp.AutoMapper 包中的 AutoMapper 实现这个接口。

注意:需要将Abp.AutoMapper NuGet 包安装到您的项目中:
public class UserAppService : ApplicationService
{
    private readonly IRepository<User> _userRepository;
    private readonly IObjectMapper _objectMapper;

    public UserAppService(IRepository<User> userRepository, IObjectMapper objectMapper)
    {
        _userRepository = userRepository;
        _objectMapper = objectMapper;
    }

    public void CreateUser(CreateUserInput input)
    {
        var user = _objectMapper.Map<User>(input);
        _userRepository.Insert(user);
    }
}
IObjectMapper 是一个简单的抽象,它具有将一个对象映射到另一个对象的 Map 方法。
Map 是一个简单的方法,它获取源对象并创建一个新的目标对象,其类型声明为通用参数(本示例中的 User)。Map 方法具有将对象映射到现有对象的重载 。假设我们已经有一个 User 实体并且想要使用一个对象更新它的属性:
public void UpdateUser(UpdateUserInput input)
{
    var user = _userRepository.Get(input.Id);
    _objectMapper.Map(input, user);
}
大多数时候,您可能只想直接(和传统地)映射类。在这种情况下,您可以使用AutoMap、AutoMapFrom和AutoMapTo 属性。例如,如果我们想将CreateUserInput类映射到上面示例中的User类,我们可以使用AutoMapTo属性,如下所示:
[AutoMapTo(typeof(User))]
public class CreateUserInput
{
    public string Name { get; set; }

    public string Surname { get; set; }

    public string EmailAddress { get; set; }

    public string Password { get; set; }
}

自定义映射

在某些情况下,简单映射可能不适合。例如,两个类的属性名称可能略有不同,或者您可能希望在映射过程中忽略某些属性。在这种情况下,您应该直接使用 AutoMapper 的 API 来定义映射。Abp.AutoMapper 包定义了一个 API 来使自定义映射更加模块化。
假设我们想在映射时忽略密码,并且用户的电子邮件属性名称略有不同。我们可以定义映射如下所示:
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
    public override void PreInitialize()
    {
        Configuration.Modules.AbpAutoMapper().Configurators.Add(config =>
        {
            config.CreateMap<CreateUserInput, User>()
                  .ForMember(u => u.Password, options => options.Ignore())
                  .ForMember(u => u.Email, options => options.MapFrom(input => input.EmailAddress));
        });
    }
}

可以使用另一种变种类型:

[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
    public override void PreInitialize()
    {
        
    }
    public override void Initialize()
    {
        var thisAssembly = typeof(MyModule ).GetAssembly();

        IocManager.RegisterAssemblyByConvention(thisAssembly);

        Configuration.Modules.AbpAutoMapper().Configurators.Add(
            cfg => cfg.AddProfile<CustomDtoMapperProfile>()
        );
    }
}

public class CustomDtoMapperProfile : Profile
{
     public CustomDtoMapperProfile()
     {
          CreateMap<CreateUserInput, User>()
                .ForMember(u => u.Password, options => options.Ignore())
                .ForMember(u => u.Email, options => options.MapFrom(input => input.EmailAddress))
                .ForMember(u => u.Name, options => options.MapFrom(input => input.Surname));
     }
}

提高

当需要将 Role、User 实体映射到一个 CreateUserInput类
public class Role
{
    public string Name { get; set; }
    public string DisplayAge{ get; set; }
}
public class User
{
    public string Code{ get; set; }
    public string Name { get; set; }
    public string Age{ get; set; }
    public string Surname { get; set; }
    public string EmailAddress { get; set; }
    public string Password { get; set; }
}

public class CreateUserInput
{
    public string UserName { get; set; }
    public string Surname { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public string Code { get; set; }
    public string Age { get; set; }
    public string RoleName { get; set; }
    public string DisplayName { get; set; }
}
public class CustomDtoMapperProfile : Profile
{
     public CustomDtoMapperProfile()
     {
          CreateMap<(Role,User), CreateUserInput>()
              .ForMember(u => u.RoleName, options => options.MapFrom(input => input.Item1.Name))
                .ForMember(u => u.Email, options => options.MapFrom(input => input.Item2.EmailAddress))
                .ForMember(u => u.UserName, options => options.MapFrom(input => input.Item2.Name));
     }
}

注:当需要将多个实体映射到一个 CreateUserInput类时,CreateMap<(XXX,XXX,XXX,....), CreateUserInput>(),会出现 Item1,Item2,Item3,Item4,Item5,依次递增

posted @ 2022-12-14 09:25  悟自省  阅读(400)  评论(0编辑  收藏  举报