JPA @Where 사용법

Posted by Yun on 2020-10-10

해당 코드는 Github 공개되어 있습니다.

JPA에서 @Where를 사용하면 엔티티를 조회하는 경우 일괄적인 Where 조건을 추가할 수 있습니다. 코드를 살펴보겠습니다.

Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Entity
@Table(name = "member")
@Where(clause = "status = 'NORMAL'")
data class Member(
@Column(name = "username", nullable = false)
var username: String,

@Column(name = "age", nullable = false)
var age: Int = 0,

@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
var status: MemberStatus = MemberStatus.NORMAL,

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id", nullable = false)
var team: Team
) : EntityAuditing() {
}

enum class MemberStatus {
NORMAL,
BAN
}

@Entity
@Table(name = "team")
data class Team(
@Column(name = "name", nullable = false)
var name: String
) : EntityAuditing() {

@OneToMany(fetch = FetchType.LAZY, mappedBy = "team")
var members: MutableList<Member> = mutableListOf()
}

엔티티는 위 코드처럼 ManyToOne <-> OneToMany 관계를 가지며 Member 엔티티의 상태를 표현하는 MemberStatus enum 클래스로 NORMAL, BAN status를 갖습니다. 일반적인 Member의 조회는 NORMAL인 status를 기준으로 한다고 가정했을 경우 엔티티 조회에서 where status = 'NOMAL'의 조건이 추가되어야 합니다. 이런 경우 @Where을 사용하면 유용합니다. 테스트 코드를 통해서 살펴보겠습니다.

Test Code

Member

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
internal fun `where sql MemberStatus BAN test`() {
//given
val teamA = save(Team("teamA"))
val memberId = save(Member("name", 10, MemberStatus.BAN, teamA)).id!!

//when
val member = memberRepository.findById(memberId)

//then
then(member.isPresent).isFalse()
println("member 조회 여부 : ${member.isPresent}")
}

member의 조회는 findById 즉 PK로 찾는 코드지만 @Where(clause = "status = 'NORMAL'")으로 인해서 SQL 로그를 보면 where 조건에 member0_.status = 'NORMAL '가 추가된 것을 확인할 수 있습니다. MemberStatus.BAN상태로 Member를 저장했기 때문에 조회 여부는 false인 것을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
internal fun `where sql MemberStatus NORMAL test`() {
//given
val teamA = save(Team("teamA"))
val memberId = save(Member("name", 10, MemberStatus.NORMAL, teamA)).id!!

//when
val member = memberRepository.findById(memberId)

//then
then(member.isPresent).isTrue()
println("member 조회 여부 : ${member.isPresent}")
}

이번에는 MemberStatus.NORMAL으로 저장하고 조회 해보겠습니다.

member 조회 여부가 true인것을 확인할 수 있습니다.

Team

그렇다면 Team 엔티티를 통해서 Lazy Loading 하는 경우에도 Member 엔티티의 @Where(clause = "status = 'NORMAL'")가 동작하는지를 QueryDSL 기반으로 진행해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
internal fun `where sql test`() {
//given
val qTeam = QTeam.team
val teamA = save(Team("teamA"))
save(Member("name", 10, MemberStatus.NORMAL, teamA))

//when
val findTeam = Optional.of(query.selectFrom(qTeam).where(qTeam.id.eq(teamA.id)).fetchOne()!!)
//then

val memberSize = findTeam.get().members.size
println("member size : $memberSize")
println("team 조회 여부 : ${findTeam.isPresent}")
}

Team 엔티티를 통해서 Member 엔티티를 Lazy Loading 하더라도 @Where(clause = "status = 'NORMAL'")가 정상적으로 동작하는것을 확인 할 수 있습니다.