[JPA] Entity 연관관계 매핑하기 - 1:1(@OneToOne), 1:N(@OneToMany), N:1(@ManyToOne), N:M(@ManyToMany)

koline·2024년 4월 30일

JPA

목록 보기
10/11

Entity 연관관계 매핑하기


이전에 Entity의 단방향/양방향 연관관계에 대해 알아봤었는데 이번에는 실제로 연관관계를 어떻게 맺는지를 알아보자.

아래의 예시들은 단방향 매핑을 기준으로 작성되었다.




1:1 매핑 (@OneToOne)


단방향

// Post.java
@Entity
public class Post {
	@Id @GeneratedValue
    @Column(name = "POST_ID")
	private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @Column(name = "CONTENT")
    private String content;
    
    @OneToOne
    @JoinColumn(name = "USER_ID", insertable = false, updatable = false)
    private User createdBy;
    
}

// User.java
@Entity
public class User {
	@Id @GeneratedValue
    @Column(name = "USER_ID")
    private Long id;
    
    @Column(name = "NAME")
    private String name;
}

양방향

// Post.java
@Entity
public class Post {
	@Id @GeneratedValue
    @Column(name = "POST_ID")
	private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @Column(name = "CONTENT")
    private String content;
    
    @OneToOne
    @JoinColumn(name = "USER_ID", insertable = false, updatable = false)
    private User createdBy;
    
}

// User.java
@Entity
public class User {
	@Id @GeneratedValue
    @Column(name = "USER_ID")
    private Long id;
    
    @Column(name = "NAME")
    private String name;
    
    @OneToOne(mappedBy = "createdBy")
    private Post post;
}

모든 게시글(Post)은 작성자(User)를 하나 반드시 가진다. 다만 실제로는 작성자는 여러 게시글을 작성할 수 있는 일대다 관계지만 하나만 작성할 수 있다고 가정하고 작성했다.




1:N 매핑 (@OneToMany)


단방향

// Board.java
@Entity
public class Board {
	@Id @GeneratedValue
    @Column(name = "BOARD_ID")
	private Long id;
    
    @Column(name = "NAME")
    private String name;
    
    @OneToMany
    @JoinColumn(name = "POST_ID", insertable = false, updatable = false)
    private List<Post> posts = new ArrayList<>();
}


// Post.java
@Entity
public class Post {
	@Id @GeneratedValue
    @Column(name = "POST_ID")
	private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @Column(name = "CONTENT")
    private String content;
}

지난 포스팅에서 단방향 매핑의 예시로 사용했던 코드이다. 게시글 Entity가 가지고있는 boardId 속성을 기준으로 게시판(1)이 게시글(N) 목록을 속성으로 가지고 있는 형태로써 상대방 속성을 가지고있는 게시판을 기준으로 1:N 매핑이 된다.




N:1 매핑 (@ManyToOne)


단방향

// Board.java
@Entity
public class Board {
	@Id @GeneratedValue
    @Column(name = "BOARD_ID")
	private Long id;
    
    @Column(name = "NAME")
    private String name;
}


// Post.java
@Entity
public class Post {
	@Id @GeneratedValue
    @Column(name = "POST_ID")
	private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @Column(name = "CONTENT")
    private String content;
    
    @Column(name = "BOARD_ID")
    private String boardId;
    
    @ManyToOne
    @JoinColumn(name = "BOARD_ID", insertable = false, updatable = false)
    private Board board;
}

양방향

// Board.java
@Entity
public class Board {
	@Id @GeneratedValue
    @Column(name = "BOARD_ID")
	private Long id;
    
    @Column(name = "NAME")
    private String name;
    
    @OneToMany(mappedBy = "board", fetch = FetchType.EAGER)
    private List<Post> posts = new ArrayList<>();
}


// Post.java
@Entity
public class Post {
	@Id @GeneratedValue
    @Column(name = "POST_ID")
	private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @Column(name = "CONTENT")
    private String content;
    
    @Column(name = "BOARD_ID")
    private String boardId;
    
    @ManyToOne
    @JoinColumn(name = "BOARD_ID", insertable = false, updatable = false)
    private Board board;
}

N:1 매핑은 1:N 매핑과 유사하지만 연관관계의 주인이 1측(게시글측)이 된다는 점에서 다르다.




N:M 매핑 (@ManyToMany)


단방향

// Board.java
@Entity
public class Board {
	@Id @GeneratedValue
    @Column(name = "BOARD_ID")
	private Long id;
    
    @Column(name = "NAME")
    private String name;
}


// Post.java
@Entity
public class Post {
	@Id @GeneratedValue
    @Column(name = "POST_ID")
	private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @Column(name = "CONTENT")
    private String content;
    
    @Column(name = "BOARD_ID")
    private String boardId;
    
    @ManyToOne
    @JoinColumn(name = "BOARD_ID", insertable = false, updatable = false)
    private Board board;
}

양방향

// Board.java
@Entity
public class Board {
	@Id @GeneratedValue
    @Column(name = "BOARD_ID")
	private Long id;
    
    @Column(name = "NAME")
    private String name;
    
    @ManyToMany(mappedBy = "boards", fetch = FetchType.EAGER)
    private List<Post> posts = new ArrayList<>();
}


// Post.java
@Entity
public class Post {
	@Id @GeneratedValue
    @Column(name = "POST_ID")
	private Long id;
    
    @Column(name = "TITLE")
    private String title;
    
    @Column(name = "CONTENT")
    private String content;
    
    @Column(name = "BOARD_ID")
    private String boardId;
    
    @ManyToMany
    @JoinTable(name = "BOARD_POST")
    private List<Board> boards = new ArrayList<>();
}

실제로 이런 경우는 없지만 한 게시글이 여러 게시판에 속할 수 있고 한 게시판이 여러 게시글을 가진 다대다 관계라고 가정하고 작성하였다.

다만 이와 같이 @ManyToMany 어노테이션을 사용한 다대다 매핑은 소스상에서 컨트롤할 수 없는 JoinTable을 생성하여 매핑하는 방식이다.

해당 테이블에 PK가 아닌 다양한 데이터가 들어갈 수 있고 제어가 불가능하며, 예상치 못한 복잡한 Join 쿼리가 발생하여 성능이 저하될 수 있다.

그러므로 다대다 매핑이 필요한 경우 직접 JoinTableEntity로 작성하여 다대일 - 일대다 로 매핑하는 것이 좋다.




참조


[JPA] Entity 연관관계 매핑하기 - 양방향/단방향

profile
개발공부를해보자

0개의 댓글