1. 개요
이 사용방법에서는 JPA를 사용하여 다 대다 관계 를 처리하는 여러 방법을 살펴 봅니다 .
우리는 학생들, 코스 및 그들 사이의 다양한 관계의 모델을 사용할 것입니다.
단순성을 위해 코드 예제에서는 다 대다 관계와 관련된 속성 및 JPA 구성 만 표시합니다.
2. 기본 다 대다
2.1. 다 대다 관계 모델링
관계는 두 유형의 엔터티 간의 연결입니다. 다 대다 관계의 경우 양쪽 모두 다른 쪽의 여러 인스턴스와 관련 될 수 있습니다.
엔티티 유형이 자신과 관계를 맺을 수 있습니다. 가계도 모델링의 예를 생각해보십시오. 모든 노드는 사람이므로 부모-자녀 관계에 대해 이야기하면 두 참가자 모두 사람이됩니다.
그러나 단일 또는 다중 엔티티 유형 간의 관계에 대해 이야기하는지 여부는 그러한 차이를 만들지 않습니다. 서로 다른 두 엔터티 유형 간의 관계에 대해 생각하는 것이 더 쉽기 때문에이를 사용하여 사례를 설명합니다.
학생들이 좋아하는 코스를 표시하는 예를 들어 보겠습니다.
학생은 여러 코스 를 좋아할 수 있으며 많은 학생이 동일한 코스를 좋아할 수 있습니다.
아시다시피 RDBMS에서는 외래 키와의 관계를 만들 수 있습니다. 양쪽 모두 다른 쪽을 참조 할 수 있어야 하므로 외래 키를 보관할 별도의 테이블을 만들어야합니다 .
이러한 테이블을 조인 테이블 이라고 합니다. 조인 테이블에서 외래 키 조합은 복합 기본 키가됩니다.
2.2. JPA에서 구현
POJO와 다 대다 관계를 모델링하는 것은 쉽습니다. 다른 클래스 의 요소를 포함하는 컬렉션 을 두 클래스 모두에 포함 해야 합니다.
그런 다음 클래스를 @Entity 로 표시 하고 기본 키를 @Id 로 표시하여 적절한 JPA 엔티티를 만들어야합니다.
또한 관계 유형을 구성해야합니다. 따라서 @ManyToMany 어노테이션으로 컬렉션을 표시합니다 .
@Entity
class Student {
@Id
Long id;
@ManyToMany
Set<Course> likedCourses;
// additional properties
// standard constructors, getters, and setters
}
@Entity
class Course {
@Id
Long id;
@ManyToMany
Set<Student> likes;
// additional properties
// standard constructors, getters, and setters
}
또한 RDBMS에서 관계를 모델링하는 방법을 구성해야합니다.
소유자 측은 관계를 구성하는 곳입니다. Student 클래스를 사용할 것 입니다.
Student 클래스 의 @JoinTable 어노테이션으로 이를 수행 할 수 있습니다 . @JoinColumn 어노테이션 을 사용하여 조인 테이블 ( course_like ) 의 이름과 외래 키를 제공합니다 . joinColumn의 특성은 관계의 소유자 측과 연결한다 inverseJoinColumn 반대편 :
@ManyToMany
@JoinTable(
name = "course_like",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id"))
Set<Course> likedCourses;
사용합니다 @JoinTable 또는 @JoinColumn하는 것은 필요하지 않습니다. JPA는 테이블 및 열 이름을 생성합니다. 그러나 JPA에서 사용하는 전략은 우리가 사용하는 명명 규칙과 항상 일치하지는 않습니다. 따라서 테이블 및 열 이름을 구성 할 수있는 가능성이 필요합니다.
대상 측에서는 관계를 매핑하는 필드의 이름 만 제공하면됩니다.
따라서, 우리는 설정 mappedBy의 의 속성 @ManyToMany의 에서 어노테이션 코스 클래스를 :
@ManyToMany(mappedBy = "likedCourses")
Set<Student> likes;
다 대다 관계는 데이터베이스에 소유자 측이 없기 때문에 Course 클래스 에 조인 테이블을 구성 하고 Student 클래스 에서 참조 할 수 있습니다 .
3. 복합 키를 사용하는 다 대다
3.1. 관계 속성 모델링
학생들이 코스를 평가하게하고 싶다고 가정 해 보겠습니다. 한 학생은 여러 코스를 평가할 수 있으며 여러 학생이 동일한 코스를 평가할 수 있습니다. 따라서 다 대다 관계이기도합니다.
이 예제를 좀 더 복잡하게 만드는 것은 평가 관계가 존재한다는 사실보다 더 많은 관계가 있다는 것입니다. 학생이 코스에 부여한 평가 점수를 저장해야합니다.
이 정보를 어디에 저장할 수 있습니까? 학생이 다른 코스에 다른 등급을 부여 할 수 있으므로 Student 엔터티 에 넣을 수 없습니다 . 마찬가지로 Course 엔터티 에 저장 하는 것도 좋은 솔루션이 아닙니다.
관계 자체에 속성 이있는 상황 입니다.
이 예제를 사용하여 관계에 속성을 첨부하는 것은 ER 다이어그램에서 다음과 같습니다.
간단한 다 대다 관계와 거의 동일한 방식으로 모델링 할 수 있습니다. 유일한 차이점은 조인 테이블에 새 속성을 추가한다는 것입니다.
3.2. JPA에서 복합 키 만들기
단순한 다 대다 관계의 구현은 다소 간단했습니다. 유일한 문제는 엔터티를 직접 연결했기 때문에 관계에 속성을 추가 할 수 없다는 것입니다. 따라서 관계 자체에 속성을 추가 할 방법이 없었습니다.
DB 속성을 JPA의 클래스 필드에 매핑하므로 관계에 대한 새 엔티티 클래스를 만들어야합니다.
물론 모든 JPA 엔터티에는 기본 키가 필요합니다. 기본 키는 복합 키이므로 키의 다른 부분을 포함 할 새 클래스를 만들어야합니다 .
@Embeddable
class CourseRatingKey implements Serializable {
@Column(name = "student_id")
Long studentId;
@Column(name = "course_id")
Long courseId;
// standard constructors, getters, and setters
// hashcode and equals implementation
}
복합 키 클래스는 몇 가지 주요 요구 사항 을 충족 해야합니다 .
- @Embeddable 로 표시해야합니다 .
- java.io.Serializable 을 구현해야 합니다.
- hashcode () 및 equals () 메서드 의 구현을 제공해야 합니다.
- 필드 자체는 엔티티가 될 수 없습니다.
3.3. JPA에서 복합 키 사용
이 복합 키 클래스를 사용하여 조인 테이블을 모델링하는 엔터티 클래스를 만들 수 있습니다.
@Entity
class CourseRating {
@EmbeddedId
CourseRatingKey id;
@ManyToOne
@MapsId("studentId")
@JoinColumn(name = "student_id")
Student student;
@ManyToOne
@MapsId("courseId")
@JoinColumn(name = "course_id")
Course course;
int rating;
// standard constructors, getters, and setters
}
이 코드는 일반 엔티티 구현과 매우 유사합니다. 그러나 몇 가지 주요 차이점이 있습니다.
- @EmbeddedId 를 사용 하여 CourseRatingKey 클래스 의 인스턴스 인 기본 키를 표시했습니다 .
- 학생 및 코스 필드를 @MapsId 로 표시했습니다 .
@MapsId 는 이러한 필드를 키의 일부에 연결하고 다 대일 관계의 외래 키임을 의미합니다. 앞서 언급했듯이 복합 키에 엔터티를 포함 할 수 없기 때문에 필요합니다.
그런 다음 이전 과 같이 Student 및 Course 엔터티 에서 역 참조를 구성 할 수 있습니다 .
class Student {
// ...
@OneToMany(mappedBy = "student")
Set<CourseRating> ratings;
// ...
}
class Course {
// ...
@OneToMany(mappedBy = "course")
Set<CourseRating> ratings;
// ...
}
복합 키를 사용하는 다른 방법 인 @IdClass 어노테이션이 있습니다.
3.4. 추가 특성
Student 및 Course 클래스에 대한 관계를 @ManyToOne으로 구성했습니다 . 새로운 엔터티를 사용하여 다 대다 관계를 두 개의 다 대일 관계로 구조적으로 분해했기 때문에 이렇게 할 수 있습니다.
왜 우리가 이것을 할 수 있었습니까? 이전 사례에서 테이블을 자세히 살펴보면 두 개의 다 대일 관계가 포함되어 있음을 알 수 있습니다. 즉, RDBMS에는 다 대다 관계가 없습니다. 우리가 모델링하는 것이기 때문에 조인 테이블 다 대다 관계로 생성 한 구조를 호출합니다.
게다가 다 대다 관계에 대해 이야기하는 것이 우리의 의도이기 때문에 더 분명합니다. 한편 조인 테이블은 구현 세부 사항 일뿐입니다. 우리는 그것에 대해 정말로 신경 쓰지 않습니다.
또한이 솔루션에는 아직 언급하지 않은 추가 기능이 있습니다. 간단한 다 대다 솔루션은 두 엔터티 간의 관계를 만듭니다. 따라서 우리는 더 많은 엔티티로 관계를 확장 할 수 없습니다. 그러나이 솔루션에는 이러한 제한이 없습니다 . 원하는 수의 항목 유형 간의 관계를 모델링 할 수 있습니다.
예를 들어 여러 교사가 한 코스를 가르 칠 수있는 경우 학생은 특정 교사가 특정 코스를 어떻게 가르치는 지 평가할 수 있습니다. 그런 식으로 등급은 학생, 코스 및 교사의 세 항목 간의 관계가됩니다.
4. 새 엔티티를 사용한 다 대다
4.1. 관계 속성 모델링
학생들이 코스에 등록 할 수 있도록하고 싶다고 가정 해 보겠습니다. 또한 학생이 특정 과정에 등록 할 때 포인트를 저장해야합니다. 또한 그녀가받은 성적을 과정에서 저장하고 싶습니다.
이상적인 세계에서는 복합 키가있는 엔티티가있는 이전 솔루션으로이 문제를 해결할 수 있습니다. 그러나 세상은 이상적인 것과는 거리가 멀고 학생들이 항상 첫 번째 시도에서 과정을 이수하는 것은 아닙니다.
이 경우 동일한 student_id-course_id 쌍이 있는 동일한 student-course 쌍 또는 여러 행 사이 에 여러 연결 이 있습니다 . 모든 기본 키가 고유해야하므로 이전 솔루션을 사용하여 모델링 할 수 없습니다. 따라서 별도의 기본 키를 사용해야합니다.
따라서 등록 속성을 보유 할 엔티티를 도입 할 수 있습니다 .
이 경우 등록 엔터티는 다른 두 엔터티 간의 관계 를 나타냅니다 .
엔티티이기 때문에 자체 기본 키가 있습니다.
이전 솔루션에서는 두 개의 외래 키로 만든 복합 기본 키가 있다는 것을 기억하십시오.
이제 두 개의 외래 키는 기본 키의 일부가 아닙니다.
4.2. JPA에서 구현
course_registration 이 일반 테이블 이 되었으므로 이를 모델링하는 일반 이전 JPA 엔티티를 만들 수 있습니다.
@Entity
class CourseRegistration {
@Id
Long id;
@ManyToOne
@JoinColumn(name = "student_id")
Student student;
@ManyToOne
@JoinColumn(name = "course_id")
Course course;
LocalDateTime registeredAt;
int grade;
// additional properties
// standard constructors, getters, and setters
}
또한 Student 및 Course 클래스 의 관계를 구성해야합니다 .
class Student {
// ...
@OneToMany(mappedBy = "student")
Set<CourseRegistration> registrations;
// ...
}
class Course {
// ...
@OneToMany(mappedBy = "courses")
Set<CourseRegistration> registrations;
// ...
}
다시 말하지만, 관계를 이전에 구성 했으므로 해당 구성을 찾을 수있는 위치 만 JPA에 알리면됩니다.
또한이 솔루션을 사용하여 이전의 학생 평가 과정 문제를 해결할 수 있습니다. 그러나 꼭 필요한 경우가 아니면 전용 기본 키를 만드는 것이 이상합니다.
또한 RDBMS 관점에서 두 개의 외래 키를 결합하여 완벽한 복합 키를 만들었 기 때문에 의미가 없습니다. 게다가, 그 복합 키는 우리가 관계에서 어떤 엔티티를 연결하는지라는 명확한 의미를 가지고있었습니다.
그렇지 않으면이 두 가지 구현 사이의 선택은 종종 단순히 개인적인 선호입니다.
5. 결론
이 기사에서는 다 대다 관계가 무엇이며 JPA를 사용하여 RDBMS에서 어떻게 모델링 할 수 있는지 살펴 보았습니다.
JPA에서 모델링하는 세 가지 방법을 보았습니다. 세 가지 모두 다음과 같은 측면에서 장점과 단점이 다릅니다.
- 코드 명확성
- DB 선명도
- 관계에 속성을 할당하는 기능
- 관계와 연결할 수있는 엔티티 수
- 동일한 엔터티 간의 다중 연결 지원
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/jpa-many-to-many
'Java' 카테고리의 다른 글
Spring Boot에서 테스트 (0) | 2021.03.08 |
---|---|
Java 8 forEach 사용방법 (0) | 2021.03.08 |
스프링 JDBC (0) | 2021.03.07 |
Java 경고 "Unchecked Cast" (0) | 2021.03.07 |
Spring Redirects 사용방법 (0) | 2021.03.07 |