본 내용은 유트브 최범균님의 강의 내용을 정리한 내용입니다.
JPA 기초 16 엔티티 간 1-N 단방향 연관 매핑
1 - N 단방향 연관 매핑
- Set
- List
- Map
1. 1-N 단방향 Set 연관 매핑 설정
- @OneToMany 어노테이션은 엔티티 간의 일대다 관계를 매핑할 때 사용합니다.
- 밑의 예제는 Role 엔티티와 Permission 엔티티 간의 일대다 매핑을 하는 예제 코드입니다.
package com.example.jpa.entity;
...
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "role")
public class Role {
@Id
private String id;
private String name;
@OneToMany // 1:N 연관 관계 명시
@JoinColumn(name = "role_id") // 조인 시 참조할 컬럼 지정
private Set<Permission> permissions = new HashSet<>();
public void addPerm(Permission perm) { // 추가
permissions.add(perm);
}
public void removePerm(Permission perm) { // 삭제
permissions.remove(perm);
}
public void removeAllPerm() { // 모두 삭제
permissions.clear();
}
}
Set 컬렉션 저장
// Step 1: Permission 엔티티 저장
Permission perm1 = new Permission("P1", "G1");
Permission perm2 = new Permission("P2", "G2");
entityManager.persist(perm1);
entityManager.persist(perm2);
// Step 2: Role 엔티티 생성 및 저장
Set<Permission> permissions = new HashSet<>();
permissions.add(perm1);
permissions.add(perm2);
Role role = new Role("R1", "ROLE1", permissions);
entityManager.persist(role);
- JPA 생성 쿼리
// Permission 엔티티 저장
Hibernate:
insert into role_perm (perm, id) values (?, ?)
Hibernate:
insert into role_perm (perm, id) values (?, ?)
// Role 엔티티 저장
Hibernate:
insert into role (name, id) values (?, ?)
Hibernate:
update role_perm set role_id=? where id=?
Hibernate:
update role_perm set role_id=? where id=?
- Role 엔티티 저장 시 permissions에 담긴 엔티티의 role_id를 업데이트 합니다.
Set 컬렉션 추가, 삭제
Permission foundPerm1 = entityManager.find(Permission.class, "P1");
Permission foundPerm3 = entityManager.find(Permission.class, "P3");
Role foundRole = entityManager.find(Role.class, "R1");
foundRole.removePerm(foundPerm1); // Set 컬렉션에서 삭제
foundRole.addPerm(foundPerm3); // Set 컬렉션에 추가
// Set 컬렉션 clear()
Role foundRole = entityManager.find(Role.class, "R1");
foundRole.removeAllPerm();
- JPA 생성 쿼리
Hibernate:
select
p1_0.role_id,
p1_0.id,
p1_0.perm
from role_perm p1_0
where p1_0.role_id=?
Hibernate:
update role_perm set role_id=null where role_id=? and id=?
Hibernate:
update role_perm set role_id=? where id=?
- Set 컬렉션의 엔티티를 삭제하는 경우 참조 컬럼(role_id)을 null로 업데이트 합니다.
- Set 컬렉션에 엔티티를 추가하는 경우 참조 컬럼(role_id)를 Role 엔티티의 id값으로 업데이트 합니다.
Hibernate:
select
p1_0.role_id,
p1_0.id,
p1_0.perm
from role_perm p1_0
where p1_0.role_id=?
Hibernate:
update role_perm set role_id=null where role_id=?
- Set 컬렉션에 clear 메서드를 사용하면 현재 Role 엔티티와 연관된 모든 Permission 엔티티의 참조 컬럼(role_id)을 null로 업데이트 합니다.
2. 1-N 단방향 List 연관 매핑 설정
- List 컬렉션 필드와 연관 매핑하는 경우에는 @OrderColumn 어노테이션을 사용하여 INDEX 값을 저장할 컬럼을 명시해야 합니다.
package com.example.jpa.entity;
...
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "question")
public class Question {
@Id
private String id;
private String text;
@OneToMany
@JoinColumn(name = "question_id")
@OrderColumn(name = "idx") // 인덱스 값 컬럼 지정
private List<Choice> choices;
public void removeChoice(Choice choice) { // 삭제
choices.remove(choice);
}
public void addChoice(Choice choice) { // 추가
choices.add(choice);
}
}
List 컬렉션 저장
// Choice 엔티티 저장
Choice c1 = new Choice("C1", "TEXT1");
Choice c2 = new Choice("C2", "TEXT2");
Choice c3 = new Choice("C3", "TEXT3");
entityManager.persist(c1);
entityManager.persist(c2);
entityManager.persist(c3);
// Question 엔티티 저장
List<Choice> choices = new ArrayList<>();
choices.add(c1);
choices.add(c2);
choices.add(c3);
entityManager.persist(new Question("Q1", "질문", choices));
- JPA 생성 쿼리
Hibernate:
insert into question (text, id) values (?, ?)
Hibernate:
update question_choice set question_id=?, idx=? where id=?
Hibernate:
update question_choice set question_id=?, idx=? where id=?
Hibernate:
update question_choice set question_id=?, idx=? where id=?
- Question 엔티티를 저장한 후 연관된 Choice 엔티티의 참조 컬럼(question_id)를 모두 업데이트 해줍니다.
List 컬렉션에 엔티티 추가, 삭제
Choice foundChoice1 = entityManager.find(Choice.class, "C1");
Choice foundChoice4 = entityManager.find(Choice.class, "C4");
Question foundQuestion = entityManager.find(Question.class, "Q1");
foundQuestion.removeChoice(foundChoice1); // Choice 엔티티 삭제
foundQuestion.addChoice(foundChoice4); // Choice 엔티티 추가
- List 컬렉션에 엔티티 추가, 삭제의 경우 Set 컬렉션과 유사하게 참조 컬럼(question_id)을 업데이트 합니다.
- 그리고 INDEX 값을 저장하는 컬럼(idx)도 업데이트 합니다.
3. 1-N 단방향 Map 연관 매핑 설정
- Map 컬렉션 필드와 연관 매핑하는 경우에는 @MapKeyColumn 어노테이션을 사용하여 Map의 Key 값이 될 컬럼을 명시해줍니다.
package com.example.jpa.entity;
...
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "doc")
public class Document {
@Id
private String id;
private String title;
private String content;
@OneToMany
@JoinColumn(name = "doc_id")
@MapKeyColumn(name = "doc_title") // Map의 키가 될 컬럼 지정
private Map<String, PropValue> props = new HashMap<>();
}
Map 컬렉션 저장
// PropValue 엔티티 저장
PropValue prop1 = new PropValue("P1", "Value1");
PropValue prop2 = new PropValue("P2", "Value2");
PropValue prop3 = new PropValue("P3", "Value3");
entityManager.persist(prop1);
entityManager.persist(prop2);
entityManager.persist(prop3);
// Document 엔티티 저장
Map<String, PropValue> props = new HashMap<>();
props.put("Key1", prop1);
props.put("Key2", prop2);
props.put("Key3", prop3);
Document document = new Document("D1", "제목1", "내용1", props);
entityManager.persist(document);
- JPA 생성 쿼리
Hibernate:
insert into doc (content, title, id) values (?, ?, ?)
Hibernate:
update doc_prop set doc_id=?, doc_title=? where id=?
Hibernate:
update doc_prop set doc_id=?, doc_title=? where id=?
Hibernate:
update doc_prop set doc_id=?, doc_title=? where id=?
- Document 엔티티 저장 후 연관 된 PropValue 엔티티의 참조 컬럼(doc_id)와 Map의 Key 컬럼(doc_title)을 업데이트 합니다.
Map 컬렉션에 추가, 삭제
Document foundDoc = entityManager.find(Document.class, "D1");
PropValue foundProp4 = entityManager.find(PropValue.class, "P4");
PropValue foundProp5 = entityManager.find(PropValue.class, "P5");
foundDoc.addProp("Key1", foundProp4); // Key1 매핑 값을 prop1 -> foundProp4로 변경
foundDoc.addProp("Key5", foundProp5); // 키 값 Key5 추가
foundDoc.removeProp("Key2"); // 키 값 Key2 삭제
- JPA 생성 쿼리
// Key1과 Key2 와 매핑된 데이터 null로 변경
Hibernate:
update doc_prop set doc_id=null, doc_title=null where doc_id=? and id=?
Hibernate:
update doc_prop set doc_id=null, doc_title=null where doc_id=? and id=?
// Key1과 Key5 업데이트
Hibernate:
update doc_prop set doc_id=?, doc_title=? where id=?
Hibernate:
update doc_prop set doc_id=?, doc_title=? where id=?
- Map 컬렉션의 키(Key2)에 매핑된 값(prop1)을 변경하는 경우 이전에 매핑된 엔티티의 참조 컬럼과 키 컬럼의 값을 null로 변경합니다.
- 그리고 새로 추가한 값(foundProp4)의 참조 컬럼과 키 컬럼의 값을 업데이트 합니다.
- Map 컬렉션에 새로운 키(Key5)와 값(foundProp5)을 추가한 경우에는 해당 엔티티의 참조 컬럼과 키 컬럼 값을 업데이트 합니다.
- Map 컬렉션에 엔티티를 삭제하는 경우 해당 엔티티의 참조 컬럼과 키 컬럼 값을 null로 업데이트 합니다.
'JPA' 카테고리의 다른 글
MemberService 테스트 중 LazyInitializationException (0) | 2024.01.26 |
---|---|
Spring JPA - 회원 엔티티, 서비스, 레포지토리 구현 (1) | 2024.01.23 |
JPA 기초 1 - 1 단방향 연관 관계 (0) | 2024.01.19 |
JPA 기초 - 값 컬렉션 Map 매핑 (0) | 2024.01.18 |
JPA 기초 - 값 컬렉션 List 매핑 (0) | 2024.01.18 |