728x90
반응형
Kotlin Result 클래스
- 작업의 성공 또는 실패를 나타내는 표준화된 방식
fun findUserAuthByBusinessAndEmail(businessId: String, email: String): Result<BusinessUserAuth> { val userAuth = businessUserAuthRepository.findByBusinessIdAndEmail(businessId, email) return if (userAuth != null) { // 성공적인 작업의 결과 Result.success(userAuth) } else { // 실패한 작업의 예외 처리 Result.failure(ServiceException(ErrorCode.BUSINESS_USER_AUTH_NOT_FOUND)) } }
Spring Data JPA 엔티티 상태 관리
- Persistable
- 엔티티 상태(신규 생성/기존 데이터)를 커스터마이징하여 판단할 수 있도록 하기 위해 사용
- 엔티티의 식별자가 DB가 아닌 애플리케이션에서 직접 생성한다면(UUID, KeyGenerator 등) 엔티티가 신규인지 기존인지 구분하기 어려움
- 사용하지 않을 경우, 식별자가 비어있지 않은 경우 엔티티를 기존 데이터로 간주해 UPDATE 를 실행하기 때문에 문제가 될 수 있다.
- 기존 JPA 방식
- INSERT: 식별자가 null 인 경우, 신규 엔티티로 간주
- UPDATE: 식별자가 null 이 아닌 경우, 기존 엔티티로 간주
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) //
package org.springframework.data.domain;
import org.springframework.lang.Nullable;
public interface Persistable
@Nullable
ID getId();
boolean isNew();
}
- entity class
- 신규 상태(new) 를 관리하기 위해 작성된 메서드와 필드
```kotlin
package com.mobiai.business.business.vo.entity
import com.mobiai.business.common.orm.AllEntity
import jakarta.persistence.*
import org.springframework.data.domain.Persistable
import java.time.LocalDateTime
import kotlin.jvm.Transient
@Entity(name = "business")
class Business(
@Id
@Column(name = "id")
val tsid: String, // 식별자
var companyName: String,
var ownerName: String,
var ownerNameFile: String,
@Column(unique = true, nullable = false)
var companyNumber: String,
var companyNumberFile: String,
var approveYn: Boolean = false,
var approvedAt: LocalDateTime? = null,
var approvedBy: String? = null,
@OneToMany(mappedBy = "business")
val businessUserAuth: MutableList<BusinessUserAuth> = mutableListOf(),
@OneToMany(mappedBy = "business")
val businessAdPlatform: MutableList<BusinessAdPlatform> = mutableListOf(),
@OneToMany(mappedBy = "business")
val project: MutableList<Project> = mutableListOf(),
// 엔티티 클래스가 Persistable 인터페이스를 상속 받고 있음
// AllEntity 는 각 엔티티 클래스에서 기본적으로 사용하는 updatedAt, updateBy 정의되어 있음
) : Persistable<String>, AllEntity() {
// JPA의 Persistable 인터페이스를 구현해 엔티티 식별자 반환
// -> Business 클래스의 ID 는 tsid 필드에 저장되어 있음
override fun getId() = tsid
// JPA가 엔티티가 새로 생성된 것인지(new) / DB에서 로드된 데이터인지 판단할 때 사용
// true: 신규 / false: 기존 엔티티
override fun isNew() = _isNew
@Transient // _isNew 필드를 DB 에 매핑하지 않고, 메모리 상에서만 유지함
private var _isNew = true // 엔티티가 신규 상태인지 추적하기 위한 플래그
@PostPersist // 엔티티가 영속성 컨텍스트에 저장된 후 호출됨
@PostLoad // 엔티티가 DB에서 로드된 후 호출됨
protected fun load() {
// DB 조회 엔티티 + 저장된 엔티티 모두 신규 상태 아님
_isNew = false // 두 경우 모두 _isNew 를 false 로 설정함
}
}
Private 필드 리플렉션 접근
엔티티 관련 데이터를 생성하고 싶은 경우, _isNew
필드가 private 로 되어있기 때문에 접근할 수 없다.
따라서, Java 리플렉션을 사용하여 private/protected 필드에 접근하고 값을 수정할 수 있다.
- getDeclaredField
그러나, Java 리플렉션을 사용하는 것은 권장되지 않으므로 테스트 전용 서브클래스 또는 테스트 팩토리 패턴을 사용해 필드 상태를 관리한다..apply { // this -> entity 객체 (ex. Business, BusinessUserAuth) this.javaClass.getDeclaredField("_isNew") // _isNew 필드 가져오기 .apply { isAccessible = true // private 필드를 외부에서 수정할 수 있도록 접근 허용 // apply 스코프 함수 바깥의 객체(컨텍스트) 참조 set(this@apply, false) // _isNew 필드를 false 로 설정 > 신규 상태가 아님 } }}
728x90
반응형
'Blog > TIL' 카테고리의 다른 글
2025-01-09 (목) (0) | 2025.01.09 |
---|---|
2025-01-08 (수) (0) | 2025.01.08 |
2025-01-06 (월) (0) | 2025.01.06 |
[240907] 이진법 (0) | 2024.09.07 |
[240906] 우선 순위 큐 (PriorityQueue) (0) | 2024.09.06 |
댓글