서비스 테이블
이제 또 다른 일반적인 경우인 다대다를 살펴보겠습니다. 작업과 직원 간에 다대다 관계가 있다고 가정해 보겠습니다 .
- 직원 테이블의 한 직원은 작업 테이블에서 많은 작업을 수행할 수 있습니다.
- 작업 테이블에서 하나의 작업을 여러 직원에게 할당할 수 있습니다.
엔터티 간의 이러한 관계를 다대다라고 합니다. 그리고 이를 SQL 레벨에서 구현하기 위해서는 추가적인 서비스 테이블이 필요합니다. 예를 들어 employee_task라고 하겠습니다.
employee_task 테이블에는 두 개의 열만 포함됩니다.
- employee_id
- task_id
특정 사용자에게 특정 작업을 할당할 때마다 이 테이블에 새 행이 추가됩니다. 예:
employee_id | task_id |
---|---|
1 | 1 |
1 | 2 |
2 | 삼 |
글쎄, 작업 테이블은 employee_id 열을 잃어야 합니다 . 작업이 한 직원에게만 할당될 수 있는 경우에만 의미가 있습니다. 작업을 여러 직원에게 할당할 수 있는 경우 이 정보를 employee_task 서비스 테이블 에 저장해야 합니다 .
테이블 수준 관계
새 테이블은 다음과 같습니다.
ID | 이름 | 직업 | 샐러리 | 나이 | 가입 날짜 |
---|---|---|---|---|---|
1 | 이바노프 이반 | 프로그램 제작자 | 100000 | 25 | 2012-06-30 |
2 | 페트로프 페트르 | 프로그램 제작자 | 80000 | 23 | 2013-08-12 |
삼 | 이바노프 세르게이 | 시험 장치 | 40000 | 서른 | 2014-01-01 |
4 | 라비노비치 모이샤 | 감독 | 200000 | 35 | 2015-05-12 |
5 | 키리엔코 아나스타샤 | 사무실 관리자 | 40000 | 25 | 2015년 10월 10일 |
6 | 바스카 | 고양이 | 1000 | 삼 | 2018-11-11 |
직원 테이블( 변경되지 않음 ) :
이 테이블에는 다음 열이 있습니다.
- ID INT
- 이름 VARCHAR
- 직업 VARCHAR
- 급여 INT
- 나이 INT
- 가입 날짜 날짜
작업 테이블은 다음과 같습니다 . Employee_id 열 (빨간색으로 표시됨)이 손실되었습니다.
ID | employee_id | 이름 | 마감 시간 |
---|---|---|---|
1 | 1 | 프런트엔드의 버그 수정 | 2022-06-01 |
2 | 2 | 백엔드의 버그 수정 | 2022-06-15 |
삼 | 5 | 커피를 사다 | 2022-07-01 |
4 | 5 | 커피를 사다 | 2022-08-01 |
5 | 5 | 커피를 사다 | 2022-09-01 |
6 | (없는) | 사무실을 청소하다 | (없는) |
7 | 4 | 즐거운 삶 | (없는) |
8 | 6 | 즐거운 삶 | (없는) |
이제 이 테이블에는 3개의 열만 있습니다.
- id - 고유한 작업 번호(및 테이블의 행)
- employee_id - (삭제됨)
- 이름 - 작업의 이름 및 설명
- 기한 - 작업을 완료해야 하는 시간
또한 employee_id 데이터가 작업 테이블에서 마이그레이션된 employee_task 서비스 테이블 도 있습니다 .
employee_id | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 삼 |
5 | 4 |
5 | 5 |
(없는) | 6 |
4 | 7 |
6 | 8 |
삭제된 컬럼을 task 테이블에 일부러 임시로 저장해두었으니 그 데이터가 employee_task 테이블로 이동한 것을 확인할 수 있습니다.
또 다른 중요한 점은 employee_task 테이블의 빨간색 줄 "(NULL) 6" 입니다. employee_task 테이블 에 없기 때문에 빨간색으로 표시했습니다 .
작업 7이 사용자 4에게 할당된 경우 employee_task 테이블에 행(4, 7)이 있어야 합니다.
작업 6이 누구에게도 할당되지 않은 경우 employee_task 테이블에 해당 작업에 대한 레코드가 없을 것입니다. 이 테이블의 최종 버전은 다음과 같습니다.
작업 테이블 :
ID | 이름 | 마감 시간 |
---|---|---|
1 | 프런트엔드의 버그 수정 | 2022-06-01 |
2 | 백엔드의 버그 수정 | 2022-06-15 |
삼 | 커피를 사다 | 2022-07-01 |
4 | 커피를 사다 | 2022-08-01 |
5 | 커피를 사다 | 2022-09-01 |
6 | 사무실을 청소하다 | (없는) |
7 | 즐거운 삶 | (없는) |
8 | 즐거운 삶 | (없는) |
employee_task 테이블:
employee_id | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 삼 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
Java 클래스 수준의 통신
그러나 엔티티 클래스 수준의 통신을 통해 완전한 주문이 가능합니다. 좋은 소식부터 시작하겠습니다.
첫째, Hibernate 에는 다대다 테이블 관계의 경우를 잘 설명할 수 있도록 하는 특별한 @ManyToMany 주석이 있습니다.
둘째, 두 개의 Entity 클래스로 여전히 충분합니다. 서비스 테이블에 대한 클래스가 필요하지 않습니다.
수업은 다음과 같습니다. 원래 형식의 Employee 클래스 :
@Entity
@Table(name="user")
class Employee {
@Column(name="id")
public Integer id;
@Column(name="name")
public String name;
@Column(name="occupation")
public String occupation;
@Column(name="salary")
public Integer salary;
@Column(name="join_date")
public Date join;
}
그리고 원래 형식의 EmployeeTask 클래스:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="deadline")
public Date deadline;
}
@ManyToMany 주석
예제에서 기존 필드를 생략하고 새 필드를 추가하겠습니다. 다음과 같습니다. 직원 클래스 :
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="employee_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name="task_id", referencedColumnName="id") )
private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}
그리고 EmployeeTask 클래스 :
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="task_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name=" employee_id", referencedColumnName="id") )
private Set<Employee> employees = new HashSet<Employee>();
}
모든 것이 복잡해 보이지만 사실은 모든 것이 단순합니다.
첫째, employee_task 서비스 테이블을 설명하는 @JoinTable 주석 (@JoinColumn과 혼동하지 말 것)을 사용합니다 .
둘째, employee_task 테이블의 task_id 열이 task 테이블의 id 열을 참조한다고 설명합니다.
셋째, employee_task 테이블의 employee_id 열이 직원 테이블의 id 열을 참조한다고 합니다.
사실, 주석의 도움으로 우리는 employee_task 테이블에 포함된 데이터와 Hibernate가 이를 어떻게 해석해야 하는지 설명했습니다.
그러나 이제 우리는 모든 직원에게 매우 쉽게 작업을 추가(및 삭제)할 수 있습니다. 또한 모든 작업에 수행자를 추가합니다.
요청 예시
이러한 ManyToMany 필드의 작동 방식을 더 잘 이해하기 위해 몇 가지 흥미로운 쿼리를 작성해 보겠습니다. 그리고 그들은 예상대로 정확하게 작동합니다.
첫째, director에 이전에 작업 필드가 있었기 때문에 이전 코드는 변경 없이 작동합니다.
EmployeeTask task1 = new EmployeeTask();
task1.description = "Do Something Important";
session.persist(task1);
EmployeeTask task2 = new EmployeeTask();
task2.description = "Nothing to do";
session.persist(task2);
session.flush();
Employee director = session.find(Employee.class, 4);
director.tasks.add(task1);
director.tasks.add(task2);
session.update(director);
session.flush();
둘째, 다른 수행자를 어떤 작업에 할당하려는 경우 다음과 같이 하는 것이 훨씬 더 쉽습니다.
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
중요한! 이 요청을 실행한 결과 작업에 실행 감독이 있을 뿐만 아니라 감독도 작업 번호 101을 갖게 됩니다.
첫째, employee_task 테이블의 감독과 작업 간의 관계에 대한 사실은 (4,101) 문자열로 저장됩니다.
둘째, @ManyToMany 주석 이 표시된 필드는 프록시 객체이며 액세스할 때 항상 데이터베이스 쿼리가 실행됩니다.
따라서 직원에게 작업을 추가하고 직원에 대한 정보를 데이터베이스에 저장하면 그 후 작업은 실행자 목록에 새 실행자를 갖게 됩니다.