ABP AutoMapper與自定義Mapping

2022-12-14 12:01:52

物件對映

在工作中,需要將相似的物件對映到另一個物件,這樣我們來看一個最繁瑣的對映方式
例:
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));
     }
}