TIL

다대다 관계에서 중간테이블 만들기 / 순환참조 해결

우성팔 2024. 1. 3.

문제

다대다 관계를 가지는 entity간 연관관계 설정

 

원인

관계형 데이터베이스에서는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없고 @ManyToMany로 만들어진 연결 테이블에는 추가적인 데이터들을 추가할 수가 없음. 그리고 예상하지 못한 쿼리들이 발생함에 따라 성능이 저하됨

 

해결

두 테이블 사이에 연결 테이블(조인 테이블)을 직접 만들고 entity로 승격시켜주어 관계를 일대다, 다대일 관계로 풀어줌(@ManyToMany 사용 지양)

 

User entity

public class User {

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

    @Column(nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<UserBoard> userBoardList = new ArrayList<>();
}

 

 

Card entity

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

    @Column
    private String title;

    @Column
    private String description;

    @Column(name = "background_color")
    private String backgroundColor;

    @Column
    private Integer sequence = 1;

    @Column(name = "due_date")
    private LocalDateTime dueDate;

    
    @OneToMany(mappedBy = "card", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<UserCard> userCardList;
}

 

 

UserCard entity(중간 테이블)

public class UserCard {

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

    @ManyToOne
    @JoinColumn(name = "card_id", nullable = false)
    private Card card;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    public UserCard(User user, Card card) {
        this.user = user;
        this.card = card;
    }
}

User와 Card가 @ManyToMany로 연결하는게 아니라 중간에 테이블을 임의로 만들어 @OneToMany로 연결해주면 됨


문제

서로가 서로를 참조하는 순환참조가 발생

 

원인

반환 타입을 entity자체를 리턴하였더니 양방향 매핑이 되었음

 

해결

@JsonIgnore 어노테이션을 사용해서 해당 필드는 null로 들어가게 함

(+ @JsonManagedReference와 @JsonBackReference를 사용해서 부모 클래스에 @JsonManagedReference,

자식 클래스에 @JsonBackReference 어노테이션을 추가해줘도 됨

/ entity를 반환하지 말고 DTO를 통해서 반환해도 해결 가능)

 

Card entity로 반환하던 것을

 

Dto로 반환을 해주면 순환참조를 방지할 수 있게 됨

 

혹은 

 

순환참조가 일어나는 것에다가

@OneToMany(mappedBy = "card", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnore
private List<UserCard> userCardList;

@JsonIgnore 어노테이션을 달아줌

댓글