JPA/JPA 기본

20. 1:N 일대다

sdafdq 2023. 10. 24. 13:22

1이 연관관계의 주인일 경우.

 

테이블이 아니라 객체상의 경우를 말하는 거다.

 

근데 이 관계는 권장하지 않는다.

 

일단, 이 모델은 거의 사용하지 않는다고 보면 된다.

 

물론 객체 입장에서는 team이 member들을 가지고 있는거니 좋아보이긴 하지만..

또 뭐 Member입장에서 team을 알고 싶지 않다 그럴 수도 있고.

 

DB상에서는 무조건 다 쪽에 외래키가 있다.

즉 다쪽인 MEMBER에 외래키.

 

 

그러면 1 쪽(team)을 연관관계 주인으로 보면,

만약 팀 변경 시 Team을 통해서 다른 테이블인 MEMBER 테이블의 외래키를 update 처리 해 줘야 한다.

 

즉, 다른 테이블 이기 때문에, (그렇다고 Member가 주인이 아니라 Member로 반영도 못하고) 결국 Team으로 저장을 해야 하는데, 근데 그러면 다른 테이블이기 때문에 update 문이 한번 더 나간다.

Member가 주인이었으면 그냥 Member insert 할 때 값을 같이 넣어주면 됐었는데.

 

 

사실 update 쿼리 한번 날린 건 그렇게 문제가 아니라고 생각하지만,

 

다른 사람이 이어서 개발할 때 나는 분명 Team만 손댔는데 왜 Member에 update하지?

이런 꺼림칙 함을 느끼게 할 수 있다.

 

그리고 테이블이 뭐 지금처럼 한 두개도 아닐테고..

 

 

그냥 이렇게 하지말고,

연관관계 주인을 외래키 가지고 있는 테이블로 했다가,

그래도 뭔가 다른 쪽도 가지고 있는 게 훨씬 좋은, 거의 짝꿍인 그런 상황에서 그냥 양방향을 쓴다.

 

그리고 @JoinColumn을 꼭 사용해야 함. 

안 넣으면 Column을 찾는 게 아니라 

중간에 테이블 하나를 추가함.

 

 

그냥, 다대일 연관관계 주인 사용하셈

 

 

일단 코드

@Entity
public class Member {
    public Member() {
    }

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name="USERNAME", nullable = false)
    private String name;
}

 

@Entity
public class Team {
    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
    @OneToMany
    @JoinColumn(name = "TEAM_ID")
    private List<Member> members = new ArrayList<>();
}

이러면 

 

Member member = new Member();
member.setName("memberA");
em.persist(member);

Team team = new Team();
team.setName("TeamA");
team.getMembers().add(member);

em.persist(team);

tx.commit();

이렇게 새로 등록 시

Hibernate: 
    /* insert for
        hellojpa.Member */insert 
    into
        Member (USERNAME,MEMBER_ID) 
    values
        (?,?)
Hibernate: 
    /* insert for
        hellojpa.Team */insert 
    into
        Team (name,TEAM_ID) 
    values
        (?,?)
Hibernate: 
    update
        Member 
    set
        TEAM_ID=? 
    where
        MEMBER_ID=?

로그 보면 그냥 insert 뿐 아니라 

MEMBER 테이블도 바꿔야 하므로 MEMBER테이블에 추가적으로 update 함.

team과 연결된 테이블인 TEAM에 외래키가 있는 게 아니라 MEMBER 테이블에 외래키가 있으므로 거기를 수정해야 하기 때문에 추가로 update를 해야 함.

team꺼였으면 그냥 insert 할 때 바꾸면 됐을텐데.

 

이런 성능 상 단점도 있고,

직관적이지도 않으며,

나는 Team을 손댄 것 같은 데 뜬금없이 MEMBER 테이블이 바뀜.

 

 

 

만약 양방향을 사용하고 싶다,

지원하지는 않음.

근데

@ManyToOne
@JoinColumn(name = "TEAM_ID",insertable = false, updatable = false)
private Team team;

이렇게 Member에 추가해서 유사하게 만들 수 있긴 함.

insert, update 막아서 읽기전용으로

 

그냥 다대일 양방향을 쓰자.