객체와 테이블간의 연관관계
- 객체의 연관관계는 단방향만 존재한다. 객체의 방향성을 가지고 있기 때문에 연관관계에서 양방향 관계는 서로 단방향 연관관계를 가지고 있는것을 말한다.
- DB는 방향성이 없다. FK하나로 두 테이블의 연관관계를 관리한다.
- 객체의 양방향 연관관계를 매핑할 때는 주인을 지정해야한다.
양방향 매핑 규칙
- mappedBy를 사용해 하나의 객체를 연관관계의 주인(Owner)으로 지정한다.
- Owner가 아닌 객체에서 mappedBy를 사용해 설정한다.
- Owner에서는 JoinColumn
- 연관관계의 주인만 외래키를 관리한다.
- 두 개의 객체를 모두 업데이트 해도 연관관계의 주인인 객체만 DB에 영향이 간다.
OneToOne(일대일)
- @OneToOne(optional = true)가 default이다. 이는 null을 허용함을 의미한다.
- 실제 db생성 query에서는 contact_info_id로 생성을 하고, 조회시에는 join을사용해 결과를 반환해준다.
- optional이 true이면(default) left outer join이 수행되어 반환되고
- optional이 false이면 inner join이 수행된다.
- OneToOne Entity를 서로 가지고 있다면 Entity method를 사용할 때 ToString같은 method에서 순환 참조가 발생한다. 따라서 relation은 단방향으로 걸거나 ToString같은 method를 제외하는 처리가 필요하다.
@ToString.Exclude로 해당 field를 ToString에서 제외할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
@Entity @Data @NoArgsConstructor @AllArgsConstructor @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToOne(mappedBy = "user") // 연관관계의 주인 설정 contactInfo에서 FK 관리 @ToString.Exclude ContactInfo contactInfo; }
OneToMany(일대다)
@OneToMany
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
@Data @NoArgsConstructor @AllArgsConstructor @RequiredArgsConstructor @Entity public class Team { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NonNull private String name; @OneToMany(fetch = FetchType.EAGER) private List<Member> Members = new ArrayList<>(); //null pointer exception 발생하지 않도록 List default 생성자 호출 }
@JoinColumn
join할 때 Entity가 어떤 column으로 join할지 나타내는 Annotation이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
@Data @NoArgsConstructor @AllArgsConstructor @RequiredArgsConstructor @Entity public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NonNull private String name; @ManyToOne @JoinColumn(name = "team_id", insertable = false, updatable = false) private Team team; }
- insertable : true일 경우 Entity저장 시 해당 필드도 같이 저장한다. 읽기 전용으로 사용할 경우 false로 설정해 데이터베이스에 저장하지 않도록한다.
- updatable : insertable과 동일하며 update할 때 적용된다.
ManyToOne(다대일)
- @OneToMany에서는 참조되는 값을 One에서 가지고 있지 않는다. One에 해당하는 PK값을 Many에서 FK로 가지고 있게된다.
- 즉 User Table에서는 Team의 id를 가지고 있는다.
- 반대로 @ManyToOne은 해당 Entity가 필요로 하는 FK값을 가지고 있다.
- JPA에서는 연관된 객체를 FK를 통해 조회하는것이 아니라 Getter를 통해 가져온다. @ManyToOne을 사용할지, @OneToMany를 사용할지 양방향으로 사용할지 결정하는 조건은 어느 entity에서 연관 entity가 필요한지 생각해보면 알 수 있다.
ManyToMany(다대다)
- @OneToMany , @ManyToOne의 경우 one쪽의 id를 Many쪽에서 FK로 가지고 있는다 (@JoinColumn을 통해 중간 table생성 안되게 할 수 있음)
- OneToMany, ManyToOne에서는 JoinColumn을 사용해 중간 Table을 없애고 직접 참조를 할 수 있게 했다.
- @ManyToMany에서는 FK로 사용 할 PK를 구하기 어렵다.
- 중간 테이블을 반드시 사용해야 한다.
- 보통 ManyToMany는 많이 사용되지 않는다.