๋ณตํฉ ํค(Composite Key)
์ฌ๋ฌ ์ด์ ์กฐํฉํ์ฌ ๊ธฐ๋ณธ ํค(Primary Key)์ ์ญํ ์ ํ ์ ์๋๋ก ๋ง๋ ํค๋ฅผ ์๋ฏธํฉ๋๋ค.
์๋ณ ๊ด๊ณ
๋ถ๋ชจ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค๋ฅผ ๋ด๋ ค๋ฐ์์ ์์ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค + ์ธ๋ ํค๋ก ์ฌ์ฉํ๋ ๊ด๊ณ์ ๋๋ค.
๋น์๋ณ ๊ด๊ณ
๋ถ๋ชจ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค๋ฅผ ์์ ํ ์ด๋ธ์ ์ธ๋ ํค๋ก๋ง ์ฌ์ฉํ๋ ๊ด๊ณ์ ๋๋ค.
๋น์๋ณ ๊ด๊ณ๋ ํ์์ ๋น์๋ณ ๊ด๊ณ์ ์ ํ์ ๋น์๋ณ ๊ด๊ณ๊ฐ ์์ต๋๋ค.
ํ์์ ๋น์๋ณ ๊ด๊ณ(Mandatory)
์ธ๋ ํค์ NULL์ ํ์ฉํ์ง ์์ต๋๋ค.
์ฐ๊ด๊ด๊ณ๋ฅผ ๋ฐ๋์ ๋งบ์ด์ผ ํฉ๋๋ค.
์ ํ์ ๋น์๋ณ ๊ด๊ณ(Optional)
์ธ๋ ํค์ NULL์ ํ์ฉํฉ๋๋ค.
์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ์์ง ๋ง์ง ์ ํํ ์ ์์ต๋๋ค.
์๋ณ ๊ด๊ณ์ ๋น์๋ณ ๊ด๊ณ์ ์ ํ
์ต๊ทผ์๋ ๋น์๋ณ ๊ด๊ณ๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๊ณ ๊ผญ ํ์ํ ๊ณณ์๋ง ์๋ณ ๊ด๊ณ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์์ฆ ์ถ์ธ๋ผ๊ณ ํฉ๋๋ค.
๋ณตํฉ ํค ๋งคํ
JPA ์์๋ ์์์ฑ ์ปจํ ์คํธ์ ์ํฐํฐ๋ฅผ ๋ณด๊ดํ ๋, ์ํฐํฐ์ ์๋ณ์๋ฅผ ํค๋ก ์ฌ์ฉํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ณ์๋ฅผ ๊ตฌ๋ถํ๊ธฐ ์ํ์ฌ equals์ hashCode๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ฑ์ฑ(equals) ๋น๊ต๋ฅผ ํฉ๋๋ค.
์๋ณ์ ํ๋๊ฐ ํ๋์ธ ๊ฒฝ์ฐ์๋ ๋ณดํต Long ํ์ ์ ์ฌ์ฉํ๋ฏ๋ก ๋ฌธ์ ๋์ง ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์๋ณ์ ํ๋๊ฐ 2๊ฐ ์ด์(๋ณตํฉํค)์ด๋ผ๋ฉด ๋ณ๋์ ์๋ณ์ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , ๊ทธ๊ณณ์์ equals์ hashCode๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
JPA์์๋ ๋ณตํฉ ํค๋ฅผ ์ง์ํ๊ธฐ ์ํ์ฌ @IdClass์ @EmbeddedId 2๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
@IdClass๋ RDB์ ๊ฐ๊น์ด ๋ฐฉ๋ฒ์ ๋๋ค.
@EmbeddedId๋ ์ข ๋ ๊ฐ์ฒด์งํฅ์ ๊ฐ๊น์ด ๋ฐฉ๋ฒ์ ๋๋ค.
@IdClass๋ณด๋ค๋ @EmbeddedId๋ฅผ ์ค์ ์ ์ผ๋ก ๋ค๋ฃจ๊ณ , ๋ง์ง๋ง์ @IdClass์ ๋ํ ์ฌ์ฉ ์์๋ฅผ ๊ฐ๋จํ๊ฒ ์๊ฐํ๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ณตํฉ ํค์ @GenerateValue
๋ณตํฉ ํค์๋ @GenerateValue๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ณตํฉ ํค๋ฅผ ๊ตฌ์ฑํ๋ ์ฌ๋ฌ ์ปฌ๋ผ ์ค ํ๋์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
(2023-12-1 ์ถ๊ฐ:
https://github.com/hibernate/hibernate-orm/commit/c558fb7a5caa3557b1e9e2de7c77eff4bf608f06
์ ์ปค๋ฐ์ผ๋ก ์ธํด Hibernate 6.4.0 ๋ฒ์ ๋ถํฐ๋ ๋ณตํฉ ํค๋ฅผ ๊ตฌ์ฑํ๋ ์ฌ๋ฌ ์ปฌ๋ผ ์ค ํ๋์ GenerateValue๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋ ๊ฒ ๊ฐ์ต๋๋ค. )
@EmbeddedId
@EmbeddedId๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ์กฐ๊ฑด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- @Embeddable ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ์ด์ผ ํฉ๋๋ค.
- Serializable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
- equals, hashCode๋ฅผ ๊ตฌํํ์ฌ์ผ ํฉ๋๋ค.
- ๊ธฐ๋ณธ ์์ฑ์๊ฐ ์์ด์ผ ํฉ๋๋ค.
- ์๋ณ์ ํด๋์ค๋ public์ด์ด์ผ ํฉ๋๋ค.
๋ณตํฉ ํค + ๋น์๋ณ ๊ด๊ณ ๋งคํ
์์ ๊ด๊ณ๋ฅผ JPA๋ฅผ ํตํด ๋งคํํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
@Embeddable
class ParentId(
@Column(name = "PARENT_ID1")
var id1: Long,
@Column(name = "PARENT_ID2")
var id2: Long,
) : Serializable{
override fun equals(other: Any?): Boolean {
...
}
override fun hashCode(): Int {
...
}
}
@Entity
class Parent(
@EmbeddedId
var id: ParentId,
var name: String,
) {
}
@Entity
class Child(
@Id @Column(name = "CHILD_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns(value =
[
JoinColumn(name = "PARENT_ID1", referencedColumnName = "PARENT_ID1"),//name๊ณผ referencedColumnName์ด ๊ฐ์ผ๋ฉด referencedColumnName ์๋ต ๊ฐ๋ฅ
JoinColumn(name = "PARENT_ID2", referencedColumnName = "PARENT_ID2"),
]
)
var parent: Parent,
var name: String,
) {
}
์์ฑ๋๋ ํ ์ด๋ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋ณตํฉ ํค + ์๋ณ ๊ด๊ณ ๋งคํ
@MapsId๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
@Entity
class Parent(
@Id @Column(name = "PARENT_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long,
var name: String,
) {
}
@Embeddable
class ChildId(
var parent11Id: Long,
@Column(name = "CHILD_ID")
var id: Long,
) : Serializable{
override fun equals(other: Any?): Boolean {
...
}
override fun hashCode(): Int {
...
}
}
@Entity
class Child(
@EmbeddedId
var id: ChildId,
@MapsId(value = "parent11Id")//ChildId์ ParentId ํ๋๋ช
๊ณผ ์ผ์นํด์ผ ํจ, ์ปฌ๋ผ๋ช
์ด ์๋๋ผ ํ๋๋ช
์
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_ID")
var parent: Parent,
var name: String,
) {
}
์์ฑ๋๋ ํ ์ด๋ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์๋ณ, ๋น์๋ณ ๊ด๊ณ์ ์ฅ๋จ์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ ๊ด์ ์ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์๋ณ ๊ด๊ณ๋ณด๋ค ๋น์๋ณ ๊ด๊ณ๋ฅผ ์ ํธํฉ๋๋ค.
- ์๋ณ ๊ด๊ณ๋ ๋ถ๋ชจ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค๋ฅผ ์์ ํ ์ด๋ธ๋ก ์ ํํ๋ฉด์ ์์ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค ์ปฌ๋ผ์ด ์ ์ ๋์ด๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ถ๋ชจ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค ์ปฌ๋ผ์ด ํ๋์ด์ง๋ง, ์์์ 2๊ฐ, ์์๋ 3๊ฐ๋ก ์ ์ ๋์ด๋ฉ๋๋ค. ๊ฒฐ๊ตญ ์กฐ์ธํ ๋ SQL์ด ๋ณต์กํด์ง๊ณ , ๊ธฐ๋ณธ ํค ์ธ๋ฑ์ค๊ฐ ๋ถํ์ํ๊ฒ ์ปค์ง ์ ์์ต๋๋ค.
- ์๋ณ ๊ด๊ณ๋ 2๊ฐ ์ด์์ ์ปฌ๋ผ์ ํฉํด์ ๋ณตํฉ ๊ธฐ๋ณธ ํค๋ฅผ ๋ง๋ค์ด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
- ์๋ณ ๊ด๊ณ๋ฅผ ์ฌ์ฉํ ๋ ๊ธฐ๋ณธ ํค๋ก ๋น์ฆ๋์ค ์๋ฏธ๊ฐ ์๋ ์์ฐ ํค ์ปฌ๋ผ์ ์กฐํฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ๋ฐ๋ฉด์ ๋น์๋ณ ๊ด๊ณ์ ๊ธฐ๋ณธ ํค๋ ๋น์ฆ๋์ค์ ์ ํ ๊ด๊ณ์๋ ๋๋ฆฌ ํค๋ฅผ ์ฃผ๋ก ์ฌ์ฉํฉ๋๋ค. ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ์ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ธ์ ๊ฐ๋ ๋ณํ๊ธฐ์ ์๋ณ ๊ด๊ณ์ ์์ฐ ํค ์ปฌ๋ผ๋ค์ด ์์์ ์์๊น์ง ์ ํ๋๋ฉด ๋ณ๊ฒฝํ๊ธฐ ํ๋ค์ด์ง๋๋ค.
- ์๋ณ ๊ด๊ณ๋ ๋ถ๋ชจ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค๋ฅผ ์์ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค๋ก ์ฌ์ฉํ๋ฏ๋ก ๋น์๋ณ ๊ด๊ณ๋ณด๋ค ํ ์ด๋ธ ๊ตฌ์กฐ๊ฐ ์ ์ฐํ์ง ๋ชปํฉ๋๋ค.
๊ฐ์ฒด ๊ด๊ณ ๋งคํ์ ๊ด์ ์์ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ๋น์๋ณ ๊ด๊ณ๋ฅผ ์ ํธํฉ๋๋ค.
- ์ผ๋์ผ ๊ด๊ณ๋ฅผ ์ ์ธํ๊ณ ์๋ณ ๊ด๊ณ๋ 2๊ฐ ์ด์์ ์ปฌ๋ผ์ ๋ฌถ์ ๋ณตํฉ ๊ธฐ๋ณธ ํค๋ฅผ ์ฌ์ฉํฉ๋๋ค. JPA์์ ๋ณตํฉ ํค๋ ๋ณ๋์ ๋ณตํฉ ํค ํด๋์ค๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ์ ํฉ๋๋ค. ๋ฐ๋ผ์ ์ปฌ๋ผ์ด ํ๋์ธ ๊ธฐ๋ณธ ํค๋ฅผ ๋งคํํ๋ ๊ฒ๋ณด๋ค ๋ง์ ๋ ธ๋ ฅ์ด ํ์ํฉ๋๋ค.
- ๋น์๋ณ ๊ด๊ณ์ ๊ธฐ๋ณธ ํค๋ ์ฃผ๋ก ๋๋ฆฌ ํค๋ฅผ ์ฌ์ฉํ๋๋ฐ, JPA๋ @GenerateValue์ฒ๋ผ ๋๋ฆฌ ํค๋ฅผ ์์ฑํ๊ธฐ ์ํ ํธ๋ฆฌํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ ์๋ณ ๊ด๊ณ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ด๋ฅผ ์ฌ์ฉํ์ง ๋ชปํฉ๋๋ค.
์ ํ์ ๋น์๋ณ ๊ด๊ณ์ ํ์์ ๋น์๋ณ ๊ด๊ณ
์ ํ์ ๋น์๋ณ ๊ด๊ณ๋ณด๋ค๋ ํ์์ ๋น์๋ณ ๊ด๊ณ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ ํ์ ์ธ ๋น์๋ณ ๊ด๊ณ๋ NULL์ ํ์ฉํ๋ฏ๋ก ์กฐ์ธํ ๋์ ์ธ๋ถ ์กฐ์ธ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
๋ฐ๋ฉด์ ํ์์ ๊ด๊ณ๋ NOT NULL๋ก ํญ์ ๊ด๊ณ๊ฐ ์๋ค๋ ๊ฒ์ ๋ณด์ฅํ๋ฏ๋ก ๋ด๋ถ ์กฐ์ธ๋ง ์ฌ์ฉํด๋ ๋ฉ๋๋ค.
Reference
[์๋ฐ ORM ํ์ค JPA ํ๋ก๊ทธ๋๋ฐ] - ๊น์ํ
'๐๏ธ Spring > JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring Data JPA] - ์ฟผ๋ฆฌ ๋ฉ์๋ ๊ธฐ๋ฅ (0) | 2022.07.28 |
---|---|
[Spring Data JPA] - ์ค์ ๊ฐ๋ ์๊ฐ (0) | 2022.07.28 |
[JPA] save()์ ์๋ณ์๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ๋์ํ ๊น? (feat. ์ฝํ๋ฆฐ์์ JPA ์ฌ์ฉํ๊ธฐ) (3) | 2022.07.18 |
[JPA] SpringBoot Test์ ๋กค๋ฐฑ์ด ์๋ํ์ง ์๋ ๊ฒฝ์ฐ (MySQL ์ฌ์ฉ ์) (0) | 2022.05.15 |
[JPA] ์ด๋ ค์ฃผ์ธ์ (2) | 2022.03.14 |