ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JPA] 프로그래밍 : 1대다 맵핑
    JPA 2020. 4. 3. 15:51

    연관 관계

     

    • 회원과 팀
    • 회원은 하나의 팀에만 소속
    • 회원가 팀은 다대 일 관계

     

     

    관계에는 항상 두 엔티티가 존재 한다.

    • 둘 중 하나는 관계의 주인(owning)
    • 다른 쪽은 종속된 쪽 (non-owning)

    • 단반향 관계에서는 관계를 정의한 쪽(레퍼런스를 가지고 있는 쪽)이 주인

    • 관계의 주인에 매핑정보를 삽입해야 한다.

    • 양방향 관계에서는 @ManyToOne을 설정한 쪽이 주인

    • @onToMaynay(mappedBy)

    • 단방향과 마찬가지로 관계의 주인에게 매핑 관계를 설정해야 DB에 반영

     

    단방향 관계 ( N : 1 )

    @Entity
    public class Account{
    
        @Id @GeneratedValue
        private Long id;
    
        private String userName;
    }
    
    @Entity
    public class Study{
    
        @Id @GeneratedValue
        private Long id;
    
        private Strng name;
    
        @ManyToOne            // N : 1 관계
        private Account owner;  
    
    }
    
    //
    
    Account account = new Account();
    account.setUserName("user1");
    
    Study study = new Study();
    study.setName("Spring Data JPA");
    study.setOwner(account);
    
    
    Session session = entityManager.unwrap(Session.class);
    session.save(account);
    session.save(study);
    
    • Study라는 Table안에 Account PK를 갖는 외래키가 생성
    • Study가 주인(owning) / Account는 종속 된 쪽(non-owning)
    • N : 1 단방향 관계

    단방향 관계 ( 1 : N )

    @Entity
    public class Account{
    
        @Id @GeneratedValue
        private Long id;
    
        private String name;
    
        @OneToMany        // 1 : N 관계
        private Set<Study> studies = new HashSet<>();
    }
    
    @Entity
    public class Study{
    
        @Id @GeneratedValue
        private Long id;
    
        private Strng name;
    
    }

     

    • Account가 주인(owning) / Study는 종속 된 쪽(non-owning)
    • 1 : N 단방향 관계
    • @oneToMany(1 : N 관계) 설정 시, 해당 관계를 관리하는 테이블이 생성

     

    양방향 관계

    : 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리한다. 엔티티들 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 외래 키를 관리하면 된다. 

    엔티티를 양방형으로 매핑하면 서로를 참조한다. 따라서 객체의 연관관계를 관리하는 포인트는 2곳으로 늘어난다.  하지만 엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나다. 따라서 둘 사이에 차이가 발생한다. 그렇다면 둘 중 어던 관계를 사용해서 외래키를 관리해야 할까? 

    이런 차이로 인해 JPA에서는 두 객체의 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야 하는데, 이것을 연관관계의 주인(Owner)라 한다.

    -> 연관관계의 주인을 정한다는 것은 사실 외래 키 관리자를 선택하는 것 

    : 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래키를 관리(등록, 수정, 삭제)할 수 있다. 반면에 주인이 아닌 쪽은 읽기만 할 수 있다.

    @Entity
    public class Account{
    
        @Id @GeneratedValue
        private Long id;
    
        private String name;
    
        @OneToMany(mappedBy = "owner")        // 1 : N 관계
        private Set<Study> studies = new HashSet<>();
    }
    
    @Entity
    public class Study{
    
        @Id @GeneratedValue
        private Long id;
    
        private Strng name;
    
        @ManyToOne            // N : 1 관계
        private Account owner;  
    
    
    }
    

     

    • 1대다 관계에서 @ManyToOne ( N : 1 관계)로 설정 한 쪽이 주인
    • @OneToMany에 mappedBy (주인) 을 설정을 꼭 해줘야 한다. (설정하지 않으면 단방향 관계로 설정)
    • 관계의 주인에게 매핑을 설정해야 DB에 반영

     

    Account account = new Account();
    account.setUserName("user1");
    
    Study study = new Study();
    study.setName("Spring Data JPA");
    
    //관계의 주인은 study이므로 study에게 account를 매핑
    study.setOwner(account);
    
    
    Session session = entityManager.unwrap(Session.class);
    session.save(account);
    session.save(study);
    

     

    양방향 관계 주의점 

    1. 양방형 연관관계를 설정하고 가장 흔히 하는 실수는 연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하는 것이다. 데이터베이스에 외래 키 값이 정상적으로 저장되지 않으면 이것부터 의심해보자.

    public void testSaveNonOwner() {
    
    
    	Member member1 = new Member("member1", "회원1");
        em.persist(member1);
        
        Member member2 = new Memeber("member2","회원2");
        em.persist(member2);
        
        Team team1 = new Team("team1", "팀");
        team1.getMember().add(member1);
        team2.getMember().add(member2);
        
        em.persist(team1);
        
        }
        
        /// 데이터베이스 member 조회
        SELECT * FROM MEMBER;
        
        : 결과 
        member1 -> TEAM_ID = null
        member2 -> TEAM_ID = null;
        
        

    -> 이 예제 코드는 연관관계의 주인인 Member.team에 아무 값도 입력하지 않았다. 따라서 TEAM_ID 외래키 값도 Null

     

    2. 순수한 객체까지 고려한 양방향 연관관계 

    : 객체 관점에서는 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다. 양쪽 방향 모두 값을 입력하지 않으면 JPA를 사용하지 않은 순수한 객체 상태에서 심각한 문제가 발생 할 수 있다.

     

    public void test순수한객체_양방향() {
    
    	Team team1 = new Team("team1","팀1");
        Member member1 = new Member("member1", "회원1");
        Member member2 = new Member("member2", "회원2");
        
        member1.setTeam(team1);	
        member2.setTeam(team1);
        
        List<Member> members = team1.getMembers();
        
        System.out.println(member.size());
        
        
        // 결과 : 0
    
    }

     

    : JPA를 사용하지 않은 순수한 자바로만 이루어진 객체 -> 우리가 기대하는 양방향 연관관계의 결과가 아님 

    회원 <-> 팀 양방향 관계를 설정하기 위해, 

    회원 -> 팀

    팀 -> 회원

    모두 관계설정을 해줘야 한다. 

    public void test순수한객체_양방향() {
    
    	Team team1 = new Team("team1","팀1");
        Member member1 = new Member("member1", "회원1");
        Member member2 = new Member("member2", "회원2");
        
        member1.setTeam(team1);	
        team1.getMembers().add(member1);
        
        member2.setTeam(team1);
        team1.getMembers().add(member2);
        
        List<Member> members = team1.getMembers();
        
        System.out.println(members.size());
        
        
        // 결과 : 2
    
    }

     

    양방향 연관관계는 결국 양쪽 다 신경써야 한다. 

    public class Member {
    
    	private Team team;
        
        public void setTeam(Team team) {
        	
            if(this.team != null) this.team.getMembers().remove(this);
           
            this.team = team;
            team.getMembers().add(this);
        }
    
    
    }
    
    
    ...
    
    member1.setTeam(team1);
    member2.setTeam(team2); 
    
    

     

    정리

    • 단뱡향 매핑만으로 테이블과 객체의 연관관계 매핑은 이미 완료되었다.
    • 단뱡향을 양방향으로 만들면 반대방향으로 객체 그래프 탐색 기능이 추가된다.
    • 양방향 연관관계를 매핑하려면 객체에서 양쪽 방향을 모두 관리해야 한다. 

     

     

     

     

    참고 : 백기선 스프링 데이터 JPA, JPA 프로그래밍

     

    'JPA' 카테고리의 다른 글

    [JPA] 엔티니 매니저  (0) 2020.06.28
    [JPA] 엔티티 매핑  (0) 2020.04.06
    [JPA] 프로그래밍 : 엔티티 상태  (0) 2020.04.03
    [JPA] 프로그래밍 : 엔티티  (0) 2020.04.02
    [JPA] 개념  (0) 2020.04.02

    댓글

Designed by Tistory.