Dotnet Object Mapper (Automapper vs Mapster)

2024. 3. 4. 00:00ASPNET

반응형

프로젝트 개발을 하다보면 layer 구분을 하게 되고

각 layer 간에 data 가 공유가 필요하게 된다. 

공유 데이터를 interface 정의 하기 위해 share layer 등을 두어 처리하게 되는데

이게 몇몇 문제가 있다. 

 

특정 layer 에서 user 는 다음과 같이 정의 된다. 

public class User
{
    public string Name{get;set;}
    public int Age{get;set;}
    public string Email{get;set;}
}

그런데  Db 에 저장하기 위해서 orm 에서 persisten model 같은 경우 index 를 위해 다음 같이 정의 할 수도 있다. 

public class User
{
    [Key]
    public Guid Id{get;set;}
    public string Name{get;set;}
    public int Age{get;set;}
    public string Email{get;set;}
}

자 위와 같을 경우에 db 쪽 user class 와 domain 쪽 user class 가 다른 문제가 생기게 된다. 

물론 이건 이런 상황을 설명하기 위한 예시일 뿐이다.

 

이럴때 일일이 각 Property 를 matching 해주는게 너무 번거러울 수 있다. 

저런식의 한 두개 class 라면 모르겠으나 layer 간 이동이 잦아지면

점점 저런식의 class 들이 늘어나게 되고 순식간에 수십개가 되기도한다. 

 

그래서 이러한 class 간의 mapping 을 도와주는 library 가 있다. 

 

일반적으로 AutoMapper 라는 것을 많이 썼을 것이다. 

오늘이 AutoMapper 와 Mapster 라는 두가지 Library 사용법을 알아보겠다. 

사용에 차이점을 보고 여러분들이 마음에 드는 것을 활용 하시면 되겠다. 

 

AutoMapper

설치

dotnet add package AutoMapper

Program.cs

builder.Services.AddAutoMapper(Assembly.GetEntryAssembly());

 

Handler.cs

public class Add
{
    public record Command
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
    }

    public class Response : BaseResponse
    {
        public Guid Id { get; set; }
    }

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<Infrastructure.Models.User, Command>()
            .ReverseMap();
        }
    }

    public class CommandHandler(IMapper mapper)
    {
        private readonly IMapper _mapper = mapper;

        public Task<Response> Handle(Command command)
        {
            var user = _mapper.Map<Infrastructure.Models.User>(command);
            Store.Users.Add(user);
            return Task.FromResult(new Response { Result = true, Id=user.Id });
        }
    }

}

 

아래 코드를 보면 생성자에서 mapping 하는 걸 알수 있다. 

 public class MappingProfile : Profile

 

그리고 Handler 에서 Object Mapping 을 실행한다. 

var user = _mapper.Map<Infrastructure.Models.User>(command);

 

이렇게 하면 Command Type 의 class 가 Models.User  class 에 각 property 에 mapping 된다. 

 

Mapster

설치

dotnet add package Mapster

Program.cs

TypeAdapterConfig.GlobalSettings.Scan(Assembly.GetEntryAssembly()!);

Handler.cs

public class AddWithMapster
{
    public record Command
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string EmailAddress { get; set; }
    }

    public class Response : BaseResponse
    {
        public Guid Id { get; set; }
    }

    public class CommandHandler()
    {
        public Task<Response> Handle(Command command)
        {
            var user =command.Adapt<Infrastructure.Models.User>();
            Store.Users.Add(user);
            return Task.FromResult(new Response { Result = true, Id=user.Id });
        }
    }

}

 

 자 위에서 보면 command 객체에 extension mehtod 로 Adat 가 있어서 바로 적용하면 user 가 나오게 된다. 

기본 mapping 은 같은 이름을 기준으로 가능한 type 들이 mapping 되는 방식인것 같다. (정확하지는 않음)

 

그런데 위에서는 문제가 하나 있다. EmailAddress 에 대한 처리가 안될 것이다. 

왜냐하면 user 에는 EmailAddress 가 없고 Email 로 정의 되어 있기 때문이다. 

이런경우들이 빈번 하기 때문에 config 이 필요하다. 

다음을 추가 하자 

public class MappingRegister : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.NewConfig<Command, Infrastructure.Models.User>()
              .Map(dest => dest.Email, src => src.EmailAddress);
    }
}

 

자 이제 다시 실행해보면 정상적으로 EmailAddress 도 mapping 되는것을 확인 할 수 있다. 

 

AutoMapper 와 비교해서 편한 부분이 있고 속도가 빠르다고 하는 부분도 있다. 

쉽게 사용할 수 는 있으나 만약 EF Core 와 여러가지로 같이 연계해서 사용하다면

AutoMapper 만큼의 확장성을 갖고 있지는 않다. 

이부분 참고해서 사용 바란다. 

자 취향것!!

 

관련영상

https://youtu.be/RZjf8rwiS0c

반응형

'ASPNET' 카테고리의 다른 글

MediatR vs Wolverine  (1) 2024.02.26
Dotnet 8 - native aot  (1) 2024.01.01
dotnet 8 으로 migration 하기  (1) 2023.11.27