본문 바로가기
Back-end/카카오테크캠퍼스

[카카오테크캠퍼스] JPA 연관관계 매핑

by 잔디🌿 2024. 7. 16.

    참고!

    객체는 파스칼 표기법(Line, Station,LineStation)을 따르고, 테이블은 스네이크 표기법을 따른다(line, station, line_station)

     

    단방향 : 회원 -> 팀, 팀 -> 회원 둘 중 한 쪽만 참조하는 것

    양방향 : 회원 -> 팀, 팀 -> 회원 둘 다 참조하는 것

     

    방향은 객체관계에서만 존재하고, 테이블 관계는 항상 양방향이다.

     

    다중성

    다대일 일대다 일대일, 다대다가 있다.

     

    연관관계 주인

    객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야한다.

     

    단방향 연관관계

     

    다대일 단방향 관계

     

    회원과 팀이 있다.

    회원은 하나의 팀에만 소속될 수 있다.

    회원과 팀은 다대일 관계이다.

     

    객체 연관관계

    회원 객체는 Member.team필드를 통해 팀을 알 수 있지만, 반대로 팀은 회원을 알 수 없다.

     

    테이블 연관관계

    회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺는다.

    회원 테이블과 팀 테이블은 양방향 관계이다. 회원 테이블의 TEAM_ID 외래 키를 통해서 회원과 팀을 조회할 수 있고, 반대로 팀과 회원도 조인할 수 있다.

     

    참조를 통한 연관관계는 언제나 단방향이다. 객체간에 연관관계를 양방향으로 만드려면 반대쪽에도 필드를 추가하여 참조를 보완해야한다.

     

    객체는 참조(주소)로 연관관계를 맺고

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

     

    객체는 참조를 사용(a.getB(),a.getC()) 하지만 테이블은 조인을 사용한다.

     

    객체 관계 매핑

    @Entity
    public class Member {
        @Id
        @Column(name = "MEMBER_ID")
        private String id;
        private String username;
        //연관관계 매핑
        @ManyToOne
        @JoinColumn(name="TEAM_ID")
        private Team team;
        //연관관계 설정
        public void setTeam(Team team) {
        this.team = team;
        }
    //Getter, Setter ...
    }

    위 코드는 팀과 멤버를 연관관계 매핑한 것이다.

    팀 하나에 멤버가 여러 명 들어갈 수 있으니까 Team 필드에는 다대일 어노테이션을 작성했다.

    위와 같이 다중성 연관관계를 작성할 때에는 해당 필드를 기준으로 생각하면 된다.

     

    @Entity
    public class Team {
        @Id
        @Column(name = "TEAM_ID")
        private String id;
        private String name;
        //Getter, Setter ...
    }

    팀 엔티티는 위와 같이 작성하면 된다.

     

    @JoinColumn

    위 어노테이션은 외래키를 매핑할 때 사용된다. 위 코드에서는 Team_Id 외래키로 연관관계를 맺는다는 것을 의미한다.

    이 어노테이션은 생략 가능하고 그러면 기본적으로 필드명_참조하는 테이블의 컬럼명 외래키를 사용한다.

     

    @OneToMany
    private List<Member> members;

     

    위 코드와 같이 @~toMany 어노테이션을 가지는 필드는 리스트로 선언을 해줘야한다. 이 때 List에 제네릭을 선언해주어야한다.

     

    연관관계 사용

    연관관계를 등록,수정,삭제,조회하는 방법을 알아보자!

     

    등록

    //팀1 저장
    Team team1 = new Team("team1", "팀1");
    em.persist(team1);
    //회원1 저장
    Member member1 = new Member("member1", "회원1");
    member1.setTeam(team1); //연관관계 설정 member1 -> team1
    em.persist(member1);

     

    team1 객체를 생성하고, em.persist를 통해서 영속화한다.

    그 다음 member1의 기본 정보로 객체를 생성하고, setter을 통해서 team을 set한 다음 이를 영속화한다.

     

    주의할 점은

    JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속상태여야한다는 것이다.

     

    INSERT INTO TEAM (TEAM_ID, NAME) VALUES ('team1', '팀1')
    INSERT INTO MEMBER (MEMBER_ID, NAME, TEAM_ID) VALUES ('member1',
    '회원1', 'team1')

    JPA는 위의 SQL코드로 실행한다.

     

    조회

     

    객체 그래프 탐색

    Member member = em.find(Member.class, "member1");
    Team team = member.getTeam(); //객체 그래프 탐색
    System.out.println("팀 이름 = " + team.getName());

    객체로 연관된 엔티티를 조회한다.

     

    수정

     

    private static void updateRelation(EntityManager em) {
        //새로운 팀2
        Team team2 = new Team("team2","팀2");
        em.persist(team2);
        //회원1에 새로운 팀2 설정
        Member member = em.find(Member.class, "member1");
        member.setTeam(team2);
    }

     

    위와 같이 다시 새로운 객체를 set하면 된다.

     

    삭제

    private static void deleteRelation(EntityManager em) {
        Member member1 = em.find(Member.class, "member1");
        member1.setTeam(null); //연관관계 제거
    }

    해당 객체를 null로 set한다.

     

    양방향 연관관계

    이제까지는 회원에서 팀으로만 접근이 가능했다. 하지만 이번에는 팀에서도 회원에 접근이 가능하도록 해보려고 한다.

     

    @Entity
    public class Team {
        @Id
        @Column(name = "TEAM_ID")
        private String id;
        private String name;
        //=
        =추가=
        =//
        @OneToMany(mappedBy = "team")
        private List<Member> members = new ArrayList<Member>();
        //Getter, Setter ...
    }

    아까도 한번 언급한 부분이지만, 위와 같이 필드를 하나 추가하면 된다.

    이 때 mappedBy는 양방향 매핑일 때 사용하는데 반대쪽 매핑의 필드 이름을 값으로 주면 된다.

     

    연관관계의 주인

     

    mappedBy가 필요한 이유가 뭘까

    객체에는 양방향 연관관계라는 것이 존재하지 않는다. 그저 서로 다른 두 단방향 연관관계 2개를 애플리케이션 로직으로 묶어서 양방향으로 보이게 한 것이다. 

    이렇게 되면 객체의 연관관계를 관리하는 포인트는 2곳이 된다. 

    엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나다. 따라서 둘 사이에 차이가 발생한다. 이로 인해서 JPA는 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야하는데 이것이 연관관계의 주인이다.

     

    두 연관관계 중 주인만이 데이터베이스의 연관관계에 매핑되고, 외래키를 관리할 수 있다. 주인이 아닌 곳은 읽기만 가능하다

    어떤 연관관계를 주인으로 정할지는 MappedBy속성을 사용하면 된다.

     

    주인이 아닌 곳에 mappedBy를 설정하는 것이다.

    우리는 위에서 회원이 팀을 정할 수 있었기 때문에 팀에다가 mappedBy를 해주었다.

     

    참조

    https://product.kyobobook.co.kr/detail/S000000935744

     

    자바 ORM 표준 JPA 프로그래밍 | 김영한 - 교보문고

    자바 ORM 표준 JPA 프로그래밍 | 자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA

    product.kyobobook.co.kr