2024. 3. 4. 00:00ㆍASPNET
프로젝트 개발을 하다보면 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 만큼의 확장성을 갖고 있지는 않다.
이부분 참고해서 사용 바란다.
자 취향것!!
관련영상
'ASPNET' 카테고리의 다른 글
MediatR vs Wolverine (1) | 2024.02.26 |
---|---|
Dotnet 8 - native aot (1) | 2024.01.01 |
dotnet 8 으로 migration 하기 (1) | 2023.11.27 |