본문 바로가기
JPA/ORM 표준 JPA

05 연관관계

by clearinging 2021. 7. 28.
반응형

단방향 연관관계

객체 연관관계 와 table 관계

1 : N 관계

@Entity
public class User {
    @Id
    @Column(name = "user_id")
    private Long id;

    private String username;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="team_id")
    private Team team;
}

@Entity
public class Team {
    @Id
    @Column(name = "team_id")
    private Long id;

    private String name;
}

객체

  • user는 team을 참조 할 수 있지만, team은 user를 참조할 수 없음
  • 연관 관계 : 필드 접근 -> user.getTeam() 을 사용해서 접근

table

  • 외래키를 사용해서 양방향으로 join할 수 있음
  • join을사용해서 연관 관계 접근
  • select * from user inner join team on user.team_id = team.team_id;

Annotation

@JoinColumn

1.name

  • 기능 : mapping할 외래키 이름
  • 기본 값 : ${필드면}_${table.pk_column_name}
  1. referencedColumnName
  • 기능 : 외래 키가 참조하는 대상 table 컬럼 명
  • 기본 값 : 참조하는 table의 기본 key 컬럼 명
  1. foreignKey(DDL)
  • 기능 : 외래키 제약조건을 직접 지정, 테이블 사용할 때만 사용
  1. unique, nullable, insertable, updateable, columnDefinition, table -> @Column의 속성과 동일

@ManyToOne

  1. optional
  • 기능 : table로 설정하면 연관된 엔티티가 항상 있어야합니다.
  • 기본값 : true
  1. fetch
  • 기능 : fetch 전략을 설정
  • 기본값
    • @ManyToOne : EAGER
    • @OneToMany : LAZY
  1. cascade
  • 기능 : 연관 entity에게 전달하는 option 정보를 담는다
  1. targetEntity
  • 기능 : 연관된 Entity의 타입 정보를 설정, Collection 사용해서 generic으로 타입 정볼르 넣어줄 수 있음
@OneToMany(targetEntity=User.class)
private List users;

연관관계 기능들

저장

  1. 저장 로직
public void testSave() {
    // team1 저장
    Team team1 = new Team("team1", "팀1");
    em.perist(team1);

    // 회원 1 저장
    User user1 = new User("user1", "회원1");
    user1.setTeam(team1);
    em.persist(user1);

    User user2 = new User("user2", "회원2");
    user2.setTeam(team1);
    em.persist(user2);
}
  1. 실제 SQL실행 결과
insert into team (team_id, name) values('team1', '팀1');
insert into users(users_id, name, team_id) values('user1', '회원1', 'team1');
insert into users(users_id, name, team_id) values('user2', '회원2', 'team1');

조회

  1. 조회 방법
  • 그래프 탐색
  • JPQL 사용
  1. 그래프 탐색
User user = em.find(User.class, "user1");
Team team = user.getTeam(); // 객체 그래프 탐색 시작 -> sql이 나가는 시점
  1. JPQL
  • 기본적인 inner join으로 조회
void queryLoginJoin(EntityManager em) {
    String jpql = "select u from User u join m.team t where t.name=:teamName";
    List<User> users = em.createQuery(jpql, User.class)
    .getResultList(); // 여기서 바로 조회

      // ... codes
}
  • jpql에서 객체 들이 전부 table에 최적화된 sql으로 변환

수정

  • 수정 방법 : snapshot을 이용해서 변경
void updateRelation(EntityManager em) {
    Team team2 = new Team("team2", "팀2");
    em.persist(team2);

    User user = em.find(User.class, "user1");
    user.setTeam(team2);
}
  • 실행 sql
  • update user set team_id = 'team2' where user_id='user1';
  • 위와 같이 set 함수를 사용해서 연관 관계를 변경할 수 있습니다.

제거

void deleteRelation(EntityManager em) {
    User user = em.find(User.class, "user1");
    user.setTeam(null); // 연관 관계 제거
}

연관 관계 엔티티 삭제

  1. 순서
  • 기존에 연관관계 끊기
  • 연관관계 entity삭제
  1. 이유
  • 외래키 제약조건 때문에 삭제 이슈발생할 수 있음
user1.setTeam(null);
user2.setTeam(null);

em.remove(team1);

양방향 연관관계

패러다임 불일치

테이블은 외래키를 사용해서 양방향을 JOIN으로 조히할 수 있음, table은 양방향 관계가 아닌 단방향 관계가 2개가 이어진 경우

  • 문제점 : 어느 객체를 기준을 잡고 외래키를 update할지 의문을 가져아함
  • 해결법 : 둘중에 하나를 기준으로 설정하고, 기준이 아닌 관계는 거울인 mappedby라는 키워드를 사용한다.

mapping 방법

@Entity
public class User {
    @Id
    @Column(name = "user_id")
    private String id;
    private String username;

    @JoinColumn(name = "team_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private Team team;
}

@Entity
public class Team {
    @Id
    @Column(name="team_id")
    private String id;
    private String name;

    @OneToMany(mappedBy="team")
    private List<Member>
}
  • 연관 관계의 주인을 설정하는 방법 : 외래키를 가지고 있는 entity를 기준으로 잡는게 좋음 -> DB구조를 확인할 수 있기 때문에 좋음
  • 연관관계의 주인 : User가 된다. -> user가 team의 id 를 외래키로 가지고 있기 때문
  • mappedby : 연관관계에서 주인이 아닌 객체를 나타내기 위해서 사용한다.
    • 연과관계 주인은 mappedby를 사용하지 않는다.

양방향 연관관계시 주의점

객체에서도 양방향 관계가 적절하게 이뤄지는지 확인하기

  • 연관과계를 맺었더라도, 객체에서도 값이 잘 입력 되어 있는지 확인하는게 안전다하.
  • user1 : team1 가지고 있음
  • team1 : user2, user3을 가짐
  • -> table상에서는 user1과 team1은 연관관계이다 하지만 객체 상으로 아니다 그렇기 때문에 연관관계 편의 메소드가 필요

연곤관계 편의 메소드

  • 정의 : 양방향 관계에서 연관관계를 맺을 때 객체까지도 양방향 관계를 유지하기 위해서 사용하는 메소드
  • 예 : User함수
    private void withdrawFromTeam() {
      team.users.remove(this);
      this.team = null;    
    }
    
    

private void changeTeam(Team team) {
withdrawFromTeam(); // 연관관계 제거
team.users.add(this);
this.team = team;
}

```

  • team을 바꾸더라도 기존에 남아 있는 연관관계를 제거 해줘야 한다.
    • team1 -> team2로 바꾼다고 할때 team1에 user1이 계속 남아있을 수 있음
반응형

'JPA > ORM 표준 JPA' 카테고리의 다른 글

Fetch Join 별칭 이슈  (2) 2022.01.22
06 연관관계 Mapping 종류  (2) 2021.08.21
04 Entity  (3) 2021.07.08
03. 영속성  (0) 2021.06.30
02. JPA 요소들  (2) 2021.06.29