ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JPA] 연관관계
    기초/JPA 2022. 10. 8. 18:20

    방향

    DB테이블의 관계는 항상 양방향이다.

    객체는 한 쪽만 참조할 수 있고, 양쪽 모두 참조할 수 있다.

     

    양방향 관계

    양쪽 객체가 단방향으로 서로를 참조할수 있는 관계다.

    연관관계 주인 ( Owner )

    객체가 양방향 관계가 되면 주인을 정해야 한다.

     

    객체 그래프 탐색 

    관계가 형성된 객체는 참조를 통해 연관관계를 탐색할 수 있다.

    School school = student1.getSchool();

     

    객체 관계 매핑

    ex) Studen (M) : School (1)의 관계

    @Entity
    public class Student{
    	@Id
        private String id;
        
        @ManyToOne
        @JoinColumn(name="SCHOOL_ID")
        private School school;
        
        public void setSchool(School school) {
        	this.school = school;
        }
    }
    @Entity
    public class School{
    	@Id
        @Column(name = "SCHOOL_ID")
        private String id;
    }

    Student > School (단방향)

    이 때 School 엔티티가 Student를 바라보게 되면 양방향이 관계가 된다.

    @Entity
    public class School{
    	@Id
        @Column(name = "SCHOOL_ID")
        private String id;
        
        //추가됨
        @OneToMany(mappedBy = "student")
        private List<Student> students = new ArrayList<>();
    }

    - mappedBy 옵션 : 엔티티간의 관계에서 주인이 아닐 경우 사용

    객체에서 양방향 연관관계는 없고, 오직 서로를 바라보는 단방향 관계만 존재한다.

    테이블은 외래키 1개를 통해 두 사이의 관계를 맺지만, 객체는 양방향이 없으므로 주인을 설정으로 mappedBy 옵션을 사용한다.

    ManyToOne어노테이션은 MappedBy 옵션이 없다. 따라서 항상 주인이 되고 OneToMany 옵션에서 mappedBy 옵션을 사용하면 된다.

     

    이때 또 하나의 문제점이 있다.

    엔티티의 관계는 정리가 끝났지만 객체간의 데이터의 무결성은 성립되지 않았다.

     

    *테스트 서비스

    public class Service{
    
    	public void saveSchoolAndStudent
        	(String school, String student1, String student2) {
        	School school1 = new School("school1");
        	Student student1 = new Student("student1");
        	Student student2 = new Student("student2");
            
            student1.setSchool(school1);
            student2.setSchool(school1);
            
            List<Student> Students = school1.getStudents); // list empty
        }
    }

    Student 객체에서 setSchool을 통해 Student 객체는 School 객체안에 값이 저장되지 않았다.

    @Entity
    public class Student{
    	@Id
        private String id;
        
        @ManyToOne
        @JoinColumn(name="SCHOOL_ID")
        private School school;
        
        public void setSchool(School school) {
        	//추가 기존 매핑된 관계가 있다면 제거해 주어야 한다.
        	if(this.school != null) {
            	this.school.getStudents().remove(this);
            }
        	this.school = school;
            school.getStudents().add(this); //추가 getStudents().add 까지 리펙토링도 할수있다.
        }
    }

    이렇게 코드를 작성하게 되면 객체 데이터간의 무결성도 성립된다.

     

    *주의사항

    연관관계의 주인을 정하는 기준은 외래키의 위치다. 

    비지니스 중요도로 접근하면 안된다.

     

    양방향 관계시 그래프 참조가 무한루프에 빠지지않도록 주의한다.

    JSON 라이브러리, Lombok 라이브러리를 사용할 때 자주 발생한다.

     

    * JPA를 사용하여 모델링하게되면 데이터 중심의 설계보다는 객체 중심의 설게를 하게된다.

     

    다대다 연관관계

    다대다 관계에서 추가적인 컬럼이 필요한 경우가 대부분이다.

    따라서 관계 자체의 테이블을 하나 만들어주어 두 관계에 부가적인 컬럼을 추가해주는 일대다대일 관계를 만들어준다.

     

    Student(학생) M : Club(동아리)M 간의 관계가 정의될 때 부가적인 컬럼은 동아리 가입 시기, 동아리 가입 사유 등이 있을 수 있다. 

    Student (1) StudentClub (M) Club (1)
    - Student ID  - Student ID
     - Club ID
     - createDate
     - content
    - Club ID

    * 연결 테이블의 식별자

    식별관계 : 받아온 식별자를 기본 키 + 외래 키 로 사용

    @IdClass, @EmbeddedId 를 사용하여 구성하므로 복합키를 사용하게 된다.

     

    비식별 관계 : 받아온 식별자는 외래키, 새로운 식별자를 추가 (추천)

     

    '기초 > JPA' 카테고리의 다른 글

    [JPA] 식별관계, 비식별 관계, 복합키  (0) 2022.10.11
    [JPA] 객체간의 매핑  (0) 2022.10.11
    [JPA] JPA 어노테이션  (0) 2022.10.08
    [JPA] 영속성 컨텍스트  (2) 2022.10.08

    댓글

Designed by Tistory.