오답노트

[Spring JPA] Entity Relations 본문

Java/Spring

[Spring JPA] Entity Relations

권멋져 2023. 7. 19. 17:39

1:1 관계

Book 과 BookReviewInfo 의 1:1 관계를 나타내는 예시이다.

연결할 두 Entity에 상대방 멤버 변수를 만들고 OneToOne Annotation을 달아주면 연결된다.

OneToOne Annotation에 mappedBy를 설정하게 되면 ToString이 순환 참조로 인해 에러가 발생한다.

둘 다 사용하고 싶다면 한쪽에는 @ToString.Exclude를 사용하자.

 

OneToOne

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Book extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String category;

    private Long authorId;

    private Long publisherId;

    @OneToOne
    private BookReviewInfo bookReviewInfo;

}
@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BookReviewInfo extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 현재 테이블에 hibernate_sequence 생성
    private Long id;
    //private Long bookId;
    private float avgReviewScore;
    private int reviewCount;
    @OneToOne(optional = false)
    private Book book;

}

 

OneToOne(mappedBy)

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Book extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String category;

    private Long authorId;

    private Long publisherId;

    @OneToOne(mappedBy = "book")
    @ToString.Exclude
    private BookReviewInfo bookReviewInfo;

}

 

1:N 관계

OneToMany Annotation을 사용하여 관계를 형성한다.

해당 Entity의 JoinColumn을 사용하여 매핑 테이블이 생성되는 것을 방지 할 수 있다.

@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@Data
@Builder
@Entity
@EntityListeners(value = {UserEntityListener.class})
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class User extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NonNull
    private String name;

    @NonNull
    private String email;

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id", insertable = false, updatable = false)
    private List<UserHistory> userHistories = new ArrayList<>();
    
}

 

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class UserHistory extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_id")
    private Long userId;

    private String name;

    private String email;

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;
}

 

N:1 관계

ManyToOne으로 관계를 형성한다.

cascade 옵션은 영속성 정의라는 개념인데, Entity를 영속화 할 때, 연관된 Entity도 영속화 한다.

저장할 때만 사용하려면 cascade = CascadeType.PERSIST 로 설정해주면 되며,

전체 적용인 CascadeType.ALL 로 설정한다.

 

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Review extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String title;
    private String content;
    private float score;

    @ManyToOne(cascade = CascadeType.ALL)
    private User user;

    @ManyToOne(cascade = CascadeType.ALL)
    private Book book;


}

 

N:N 관계

ManyToMany로 관계를 형성한다.

서로 여러 개의 entity를 가지게 되므로 List 멤버 변수를 갖게 된다.

 

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Author extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String country;

    @ManyToMany
    @ToString.Exclude
    private List<Book> books = new ArrayList<>();

}

 

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Book extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String category;

    private Long authorId;

    @ManyToMany
    @ToString.Exclude
    private List<Author> authors = new ArrayList<>();


}

 

중간 테이블을 이용한 N:N 관계

N:N의 관계를 1:N 관계의 테이블을 만들어 N:N처럼 사용할 수 도 있다.

 

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)

public class Book extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String category;

    private Long authorId;

    // @ManyToMany
    @OneToMany
    @JoinColumn(name = "book_id")
    @ToString.Exclude
    private List<BookAndAuthor> bookAndAuthors = new ArrayList<>();


}

 

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Author extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String country;

    //@ManyToMany
    @OneToMany
    @JoinColumn(name = "author_id")
    @ToString.Exclude
    private List<BookAndAuthor> bookAndAuthors = new ArrayList<>();

}

 

아래는 Book과 Author 클래스를 모두 가지고 있는 BookAndAuthor 클래스를 만들었다.

 Book과 Author 클래스를 이어주는 클래스로 이 클래스로 인해  Book과 Author 클래스는 N:N관계를 간접적으로 형성하게 된다.

 

@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BookAndAuthor extends BaseEntity{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private Book book;

    @ManyToOne
    private Author author;


}