5. DTO와 AutoMapper 그리고 Repository

5-3. AutoMapper 설치, 매핑 구성

이 섹션에서는 객체 간 변환을 용이하게 하기 위해 AutoMapper를 설정하고 사용하는 방법을 배웁니다.

AutoMapper는 객체 간의 매핑을 자동화하여 수동으로 속성을 하나씩 할당하는 번거로움을 줄여줍니다.

  1. AutoMapper 설치: NuGet 패키지 관리자를 통해 AutoMapper을 설치합니다. 이를 통해 AutoMapper를 의존성 주입으로 애플리케이션에 통합할 수 있습니다.
  2. 매핑 구성 파일 생성: AutoMapper의 프로필을 상속받는 MappingConfig 클래스를 생성합니다. 이 클래스에서는 소스 객체와 대상 객체 간의 매핑을 정의합니다. 예를 들어, Plant 모델과 PlantDTO 간의 매핑, PlantCreateDTO와 PlantUpdateDTO 간의 매핑 등을 설정할 수 있습니다.
  3. 매핑 구성: CreateMap 메서드를 사용하여 소스 타입과 대상 타입 간의 매핑을 정의합니다. ReverseMap 메서드를 사용하면 양방향 매핑을 간단히 설정할 수 있습니다. AutoMapper는 속성 이름이 같을 경우 자동으로 매핑을 수행합니다. 필요한 경우 ForMember 메서드를 사용하여 커스텀 매핑을 정의할 수도 있습니다.
  4. Program.cs에서 AutoMapper 등록: Program.cs 파일에서 services.AddAutoMapper 메서드를 사용하여 MappingConfig 클래스를 등록합니다. 이렇게 하면 AutoMapper가 애플리케이션 전반에서 사용될 준비가 됩니다.
  5. API 컨트롤러에서 AutoMapper 사용: API 컨트롤러에서 IMapper 인터페이스를 의존성 주입으로 받아 객체 간 변환 작업을 수행합니다. 이를 통해 코드의 가독성과 유지 보수성을 향상시킬 수 있습니다.
  6. 객체 변환 적용:
    • 모든 식물 조회: Plant 객체 리스트를 PlantDTO 객체 리스트로 변환합니다. IMapper.Map<IEnumerable<PlantDTO>>(plantList)를 사용하여 변환을 수행합니다.
    • 단일 조회: 단일 Plant 객체를 PlantDTO로 변환합니다.
    • 생성: PlantCreateDTOPlant 객체로 변환하여 새로운 Plnat 를 생성합니다.
    • 업데이트: PlantUpdateDTOPlant 객체로 변환하여 기존 빌라 정보를 업데이트합니다.
    • 식물 부분 업데이트(Patch): Plant 객체를 PlantUpdateDTO로 변환한 후, 수정된 PlantUpdateDTO를 다시 Plant 객체로 변환하여 부분 업데이트를 수행합니다.
// MappingConfig.cs
public class MappingConfig : Profile
{
    public MappingConfig() 
    {
        CreateMap<Plant, PlantDTO>();
        CreateMap<PlantDTO, Plant>();
​
        CreateMap<Plant, PlantCreateDTO>().ReverseMap();
        CreateMap<Plant, PlantUpdateDTO>().ReverseMap();
    }
}
​
// Program.cs
builder.Services.AddAutoMapper(typeof(MappingConfig));


// PlantAPIController.cs
// 모든 식물 조회 ---//------//------//------//------//------//---
IEnumerable<Plant> plantList = await _db.Plants.ToListAsync();
return Ok(_mapper.Map<List<PlantDTO>>(plantList));
​
// 단일 조회 ---//------//------//------//------//------//---
return Ok(_mapper.Map<PlantDTO>(plant));
​
// 생성 ---//------//------//------//------//------//---
Plant model = _mapper.Map<Plant>(createDTO);
​
// AutoMapper 사용전 
//Plant model = new()
//{
//    Details = plantDTO.Details,
//    //Id = plantDTO.Id,
//    ImageUrl = plantDTO.ImageUrl,
//    Name = plantDTO.Name,
//    Occupancy = plantDTO.Occupancy,
//    Rate = plantDTO.Rate,
//    Size = plantDTO.Size
//};
await _db.Plants.AddAsync(model);
await _db.SaveChangesAsync();
​
​
// 업데이트 ---//------//------//------//------//------//---
Plant model = _mapper.Map<Plant>(updateDTO);    
​
//Plant model = new()
//{
//    Details = plantDTO.Details,
//    Id = plantDTO.Id,
//    ImageUrl = plantDTO.ImageUrl,
//    Name = plantDTO.Name,
//    Occupancy = plantDTO.Occupancy,
//    Rate = plantDTO.Rate,
//    Size = plantDTO.Size
//};
_db.Plants.Update(model);
await _db.SaveChangesAsync();
​
// 부분 업데이트(Patch): ---//------//------//------//------//---
PlantUpdateDTO plantDTO = _mapper.Map<PlantUpdateDTO>(plant);
​
Plant model = _mapper.Map<Plant>(plantDTO);
​
_db.Plants.Update(model);
await _db.SaveChangesAsync();
​

AutoMapper를 사용함으로써 객체 간 변환 로직을 간결하게 유지하면서도, 필요한 매핑을 효율적으로 관리할 수 있게 됩니다. 이는 특히 속성이 많은 복잡한 객체를 다룰 때 큰 이점을 제공합니다.