스프링 공부/JPA

[JPA] 11. 다대일, 반대로 말하면 일대다

장아장 2022. 11. 3. 21:12

연관관계의 매핑 방향성, 그리고 주인에 대한 정리가 마무리 되면, 이 매핑을 어떻게 하고 상황에 따라 주인을 어떻게 설정해야 하는지를 알아야 한다. 

 

연관관계의 객체 관계를 보고 이를 판단하게 된다. 

연관관계는 흔히 일대일, 일대다, 다대일, 다대다 로 구분된다. 

 

이중에 이번 포스팅은 다대일, 일대다를 이야기해볼 것이다. 

데이터베이스를 배울 때에는 일대다에 대해서 배운 적이 없었다. 그저 다대일이라고 이야기했을 뿐이다. 

 

JPA에 대해서 알기 전에, 데이터베이스의 다대일은 어떻게 이루어지는지 생각해보아야 한다.

다 쪽에서 외래키를 가지고, 일 쪽의 기본키를 가지게 된다. 이 외래키는 유니크하지 않다. 

그래야, 여러 객체가 한 객체의 기본키를 외래키로 가질 수 있다. 

 

다대일의 예시를 보면서 이야기하면 알기 편할 것 같다. 

@Entity
@Table(name = "ORDERS")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ORDERS_ID")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "MEMBER_ID")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Member member;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "MEMBER_ID")
private Long id;

@Column(name = "CITY")
private String city;

@Column(name = "STREET")
private String street;

@OneToMany(mappedBy = "member")
private List<Order> myOrder = new ArrayList<>();

두 개의 객체를 보면서 이야기를 이어보자면, 아까 명시했듯이 다 쪽이 외래키를 가지는, 연관관계의 주인이다. 

그렇기에 @JoinColumn(name "MEMBER_ID")로 외래키의 이름을 어떻게 저장하고, 어떻게 처리될지를 정했다. 

다(Order) : 1(Member)이기에 @ManyToOne으로 되어있다. FetchType은 후에 기술하도록 하겠다. 

 

이렇게만 해도 단방향 연관관계가 성립한다. 

 

양방향 연관관계를 위해 반대쪽 Member에 myOrder이라는 list가 @OneToMany(mappedBy = "member")라는 어노테이션을 가지고 있다. 

이는 외래키로 인해 Order에서 member라는 변수명으로 매핑되어진 객체라는 뜻이며, 이를 통해 데이터베이스에서 읽기전용으로 Order를 List로 불러올 수 있게 해준다. 

 

반대의 일대다에 대해서 정리를 하기 앞서, 잘 쓰이지 않는 다는 것을 알아야 한다. 

과연, 데이터베이스에서 여러 기본키들을 외래키 하나에 저장한다는게 가능키가 하겠나...!!!

절대 안된다. 

 

일단 이게 얼마나 복잡하냐면, 일쪽이 연관관계의 주인이지만 다 쪽이 외래키를 가진다. 일쪽은 외래키를 가질 수 없으므로...

하지만 JPA에서는 연관관계의 주인을 일 쪽으로 판단한다. 

즉, 자바에서 처리할 때에는 일 쪽이 주인인 것 같지만, 데이터베이스에 쿼리문을 날릴 땐 다 쪽이 주인인 것 처럼 쿼리를 날린다. 

주인 쪽에 @JoinColumn을 제대로 써주지 않는다면 두 테이블을 조인해서 하나의 테이블로 데이터를 가져오는 괴상한(?) 참사를 볼 수 있다. 

 

결론 : 다대일을 애용하자....