Close
Close full mode
logo만렙 개발자 키우기

(2) 일대다

Git RepositoryEdit on Github
Last update: a year ago by nowwaterReading time: 2 min
  • 일대다 관계는 다대일 관계의 반대 방향이다.
  • 일대다 관계는 엔티티를 하나 이상 참조할 수 있으므로 자바 컬렉션 Collection, List, Set, Map 중에 하나를 사용해야 한다.

6.2.1 일대다 단방향

일대다 단방향 관계 매핑 시 @JoinColumn을 명시해야 한다.

그렇지 않으면 JPA는 연결 테이블을 중간에 두고 연관관계를 관리하는 조인 테이블 전략을 기본으로 사용해서 매핑한다.

image

  • 팀 엔티티의 Team.members 로 회원 테이블의 외래 키 TEAM_ID를 관리한다.
  • 보통은 자신이 매핑한 테이블의 외래 키(다 쪽)를 관리하지만, Member 엔티티에는 외래 키를 매핑할 수 있는 참조 필드가 없다.
  • 따라서 반대편 테이블의 외래 키를 관리하는 특이한 모습이 나타난다.

일대다 단방향 매핑의 단점

  • 매핑한 객체가 관리하는 외래 키가 다른 테이블에 있다는 점

    => 연관관계 처리를 위한 UPDATE SQL을 추가로 실행해야 한다.


    *본인 테이블에 외래 키가 있으면 엔티티 저장과 연관관계 처리를 INSERT SQL 한 번에 가능*
public void testSave() {
Member member1 = new Member("member1");
Member member2 = new Member("member2");
Team team1 = new Team("team1");
team1.getMembers().add(member1);
team1.getMembers().add(member2);
em.persist(member1); // INSERT-member1
em.persist(member2); // INSERT-member2
em.persist(team1); // INSERT-team1, UPDATE-member1.fk,
// UPDATE-member2.fk
transaction.commit();
}

실행한 결과 SQL

insert into Member (MEMBER_ID, username) values (null, ?)
insert into Member (MEMBER_ID, username) values (null, ?)
insert into Team (TEAM_ID, name) values (null, ?)
update Member SET TEAM_ID=? where MEMBER_ID=?
update Member SET TEAM_ID=? where MEMBER_ID=?

Member 엔티티는 Team 엔티티를 모른다.

연관관계 정보는 Team 엔티티의 members가 관리하기 때문에 Member 엔티티를 저장할 때 MEMBER 테이블의 TEAM_ID 외래 키에 아무 값도 저장되지 않는다.

대신 Team 엔티티를 저장할 때 Team.members의 참조값을 확인해서 회원 테이블에 있는 TEAM_ID 외래 키를 업데이트한다.

일대다 단방향 매핑 대신 다대일 양방향 매핑을 사용하자

일대다 단방향 매핑 사용 시 엔티티를 매핑한 테이블이 아닌 다른 테이블의 외래 키를 관리해야 한다.

=> 성능 문제 + 관리가 부담스러움

따라서 일대다 단방향 매핑 대신 다대일 양방향 매핑을 사용한다.

다대일 양방향 매핑은 관리해야 하는 외래 키가 본인 테이블에 있다. -> 일대다 단방향 매핑 같은 문제가 발생 X

따라서 다대일 양방향 매핑 사용을 권장한다.

일대다 단방향 팀 엔티티

@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
@JoinColumn(name = "TEAM_ID") // MEMBER 테이블의 TEAM_ID (FK)
private List<Member> members = new ArrayList<Member>();
// Getter, Setter ...
...
}

일대다 단방향 회원 엔티티

@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
// Getter, Setter ...
...
}

6.2.2 일대다 양방향

일대다 양방향 매핑은 존재하지 않는다. 대신 다대일 양방향 매핑을 사용 (사실 같은 말이지만 왼쪽을 연관관계의 주인으로 가정하여 분류했기 때문에)

양방향 매핑에서 @OneToMany 는 연관관계의 주인이 될 수 없다.

=> 관계형 데이터베이스 특성상 일대다, 다대일 관계는 항상 다쪽에 외래 키가 있기 때문

따라서 @ManyToOne을 사용한 곳이 다 쪽이고, mappedBy 속성이 없다.

일대다 단방향 매핑 반대편에 같은 외래 키를 사용하는 다대일 단방향 매핑을 읽기 전용으로 하나 추가하면 가능하긴 함.

image

일대다 양방향 팀 엔티티

@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>();
// Getter, Setter ...
}

일대다 양방향 회원 엔티티

@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID", insertable = false, updatable = false) // 읽기 전용
private Team team;
// Getter, Setter ...
...
}

둘 다 같은 키를 관리해서 문제가 발생할 수 있기 때문에 반대편 다대일 쪽은 insertable = false, updatable = false 로 설정해서 읽기만 가능하게 한다.

일대다 양방향 매핑이라기 보다는 일대다 단방향 매핑 반대편에 다대일 단방향 매핑을 읽기 전용으로 추가해서 일대일 양방향처럼 보이도록 하는 방법

따라서 일대다 단방향 매핑이 가지는 단점을 그대로 가진다.

될 수 있으면 다대일 양방향 매핑을 사용하자

🚀 JPA — Previous
(1) 다대일
Next — 🚀 JPA
(3) 일대일