@ManyToMany

All lectures for KO purposes
레벨 1 , 레슨 850
사용 가능

서비스 테이블

이제 또 다른 일반적인 경우인 다대다를 살펴보겠습니다. 작업과 직원 간에 다대다 관계가 있다고 가정해 보겠습니다 .

  • 직원 테이블의 한 직원은 작업 테이블에서 많은 작업을 수행할 수 있습니다.
  • 작업 테이블에서 하나의 작업을 여러 직원에게 할당할 수 있습니다.

엔터티 간의 이러한 관계를 다대다라고 합니다. 그리고 이를 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 주석 이 표시된 필드는 프록시 객체이며 액세스할 때 항상 데이터베이스 쿼리가 실행됩니다.

따라서 직원에게 작업을 추가하고 직원에 대한 정보를 데이터베이스에 저장하면 그 후 작업은 실행자 목록에 새 실행자를 갖게 됩니다.

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION