본문 바로가기

개인적으로 공부한 것을 정리해 놓은 블로그입니다 틀린 것이 있으면 댓글 부탁 드립니다!


JPA

JPA 공부 4 - 일대다 단방향,양방향(1:N) (비추)

반응형

연관관계 매핑시 고려사항 3가지 

 

1. 다중성 

 

-  @ManyToOne , @OneToMany , @OneToOne , @ManyToMany

 

2. 단방향, 양방향 

 

-  테이블과 객체의 특성 파악 

 

테이블 

 

 외래키 하나로 양쪽 조인 가능하기 떄문에 방향이라는 개념이 없다 

 

객체

 

 참조용 필드가 있는 쪽으로 참조 가능 

 한쪽만 참조하면 단방향 양쪽이 서로 참조하면 양방향이라 한다. 

 

3. 연관관계의 주인

 

테이블은 외래  키 하나로 두 테이블이 연관관계를 맺는다 .

객체 양방향 관계는 A->B B->A  참조가 2군데서 필요하다. 둘중 테이블의 외래 키를 관리할 곳을 지정해야한다.

 

연관관계의 주인: 외래키 관리하는 참조 

주인의 반대편 : 외래 키에 영향을 주지 않으며 , 조회만 가능

 

 

일대다 단방향(1:N)

 

일대다 단방향은 1이 연관관계의 주인이 되는 경우이다 

테이블의 일대다 관계는 항상 다쪽에 외래 키가 있는데 객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조가 되어버린다 @JoinColumn을 사용해서 1쪽에 연관관계 주인임을 표시해야한다. 그렇지 않으면 JPA는  중간 테이블을 생성하는 조인 테이블 방식을 사용한다.

 

일대다 연관관계 구조

자바 엔티티 클래스로 두 객체를 살펴보자 

 

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class MemberOtM {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    
}

 

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class TeamOtM {

    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToMany
    @JoinColumn(name = "team_id")
    private List<MemberOtM> members = new ArrayList<>();

}

 

예시를 위해 one to many의 의미로 OtM이라함

 

다쪽에서 일에 대한 참조가 필요없을 떄 위와 같이 일이되는 쪽에 @OneToMany를 사용한다. 이떄 @JoinColumn으로 외래키를 지정해줘야한다 . 그래야 해당 컬럼을 외래키로 쓸 것임을 JPA가 알 수 있다. 

 

생성을해서 쿼리를 살펴보자 

 

           // 멤버 생성
            MemberOtM member = new MemberOtM();
            member.setName("member1");
            em.persist(member);
            
            //팀 생성
            TeamOtM team = new TeamOtM();
            team.setName("team1");
            //팀에 멤버 추가
            team.getMembers().add(member);

            em.persist(team);

     

멤버 생성후 팀을 생성할때 팀의 Member리스트에 위에 생성한 멤버를 넣어 줬다. 

쿼리는 몇번이 나올까 ?

 

 

멤버 ,팀  insert 2번과 멤버 update한번이 나온다. 이는 객체관계에서는 Team이 member 쪽으로 참조를 하지만 

테이블에서 외래키를 갖고 있는쪽은 member이기 떄문에 발생하는 것이다 .    

 

member를 persist할 때 insert 한번   team을 persist할때 insert 한번  member의 team_id(FK)를 updata하는 쿼리 한번 

이렇게 3번이 나가는 것이다 . 

 team을 insert하는데 member의 쿼리가 나간다 구조 상으로 유지보수가 힘들고  좋지 않은 방법이다 .

 

이렇게 사용하는 것보다는 일단 외래키를 갖은 member쪽에서 team 방향으로 단방향으로 설계를 하고 , team에서 member의 참조가 필요하다면 맵핑을 추가해주는 것이 좋다. 

 

많이 사용 되지는 않는 방법이지만 JPA 스펙에 공식적으로 나와 있는 방식이긴 하기 떄문에 이런거구나만 알면 될 것 같다 .

 

일대다 양방향(1:N)

 

 스펙상 공식적으로 나와 있는 것은 아니고 억지로 할 수 있다 잘 사용하지 않는다. 

 

반대쪽 방향에서도 @joinColumn을 걸어 주면된다. 대신 이렇게 되면 양쪽 다 연관관계의 주인이 되기 떄문에  주인이 아닌곳에 

옵션으로 insertable = false updatable = false 를 넣어줘야한다 아래 코드와 같다  주인이 아닌곳에서 조회만 가능하게 하는 것이다. 

 

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class MemberOtM {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    
    @JoinColumn(name="team_id" , insertable = false , updatable = false)
    private Team team;
}

 

 

반응형