관리 메뉴

피터의 개발이야기

[Kotlin] QueryDSL와 MapStruct를 사용하여 DTO에서 필요한 부분만 업데이트하기 본문

Programming/Kotlin

[Kotlin] QueryDSL와 MapStruct를 사용하여 DTO에서 필요한 부분만 업데이트하기

기록하는 백앤드개발자 2024. 7. 27. 10:10
반응형

ㅁ 들어가며

ㅇ Kotlin에서 QueryDSL과 MapStruct를 사용하여 DTO에서 Entity로 필요한 부분만 업데이트하는 방법을 정리하였다.

 

ㅁ 문제 상황

Kotlin Spring 프로젝트에서 QueryDSL 5.0을 사용하고 있다. 클라이언트로부터 수정 요청을 받아 DTO를 통해 Entity를 업데이트해야 하는데, MapStruct를 사용하여 필요한 부분만 적용하는 방법을 찾고 있다.

 

ㅁ 엔티티 정의

@Entity(name = "products")
data class Product(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null,
    
    @Column(name = "name")
    var name: String,

    @Column(name = "quantity")
    var quantity: Long,

    @Column(name = "registeredAt")
    var registeredAt: LocalDateTime,
)

ㅇ Product 엔티티를 작성한다.

 

ㅁ Dto 정의

data class UpdateDto(
    var id: Long,
    val name: String
)

ㅇ 클라이언트로부터 수정 요청을 받을 DTO를 작성한다.

 

ㅁ MapStruct 매퍼 인터페이스 작성

import org.mapstruct.*

@Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
interface ProductMapper {
    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
    fun updateProductFromDto(dto: ProductUpdateDto, @MappingTarget entity: Product)
}

ㅇ MapStruct를 사용하여 DTO에서 Entity로 필요한 부분만 매핑하는 매퍼 인터페이스를 작성한다.

ㅇ 기존 entity를 받아서, null값이 아닌 updateDto의 값을 치환한다.

 

ㅁ 서비스 클래스에서 매퍼 사용

import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class ProductService(
    private val productRepository: ProductRepository,
    private val productMapper: ProductMapper
) {
    @Transactional
    fun updateProduct(id: Long, updateDto: ProductUpdateDto): Product {
        val product = productRepository.findById(id).orElseThrow { RuntimeException("Product not found") }
        productMapper.updateProductFromDto(updateDto, product)
        return productRepository.save(product)
    }
}

ㅇ 서비스 클래스에서 MapStruct 매퍼를 사용하여 DTO의 값을 Entity에 반영한다.

 

ㅁ Repository 인터페이스 작성

import org.springframework.data.jpa.repository.JpaRepository

interface ProductRepository : JpaRepository<Product, Long>

ㅇ 기본적인 CRUD 작업을 위한 Repository 인터페이스를 작성한다.

 

ㅁ 마무리

  MapStruct를 사용하여 DTO에서 Entity로 필요한 부분만 업데이트할 수 있다. MapStruct의 @BeanMapping과 @MappingTarget을 활용하여 null 값은 무시하고 필요한 값만 적용할 수 있다. 이 방법을 통해 기존의 엔티티를 조회하여 필요한 부분만 업데이트하는 작업을 효율적으로 수행할 수 있다. QueryDSL과 MapStruct를 함께 사용하여 타입 안전성과 코드의 간결함을 모두 얻을 수 있다.

 

ㅁ 에필로그 @DynamicUpdate

ㅇ 변경된 필드만 업데이트 되도록 하고자 하면 다음과 같이 @DynamicUpdate 어노테이션을 붙임으로써 가능하다.

  -> 한계성: null을 업데이트 하는 경우는 

  -> 이 부분은 여기를 참조 [JPA] 더티 체킹(dirty checking)

 

 

ㅁ 함께 보면 좋은 사이트

QueryDSL with Kotlin - 기본 문법과 groupBy, 집계함수 사용

Kotlin & Querydsl 세팅

kotlin에서 queryDSL 사용하기

 

반응형
Comments