berryberrybin / board-project

0 stars 0 forks source link

[JPA] JPA 양방향 연관관계 세팅 및 주의사항 #11

Open berryberrybin opened 1 year ago

berryberrybin commented 1 year ago

두 엔티티 관계 1:N 일경우

berryberrybin commented 1 year ago

연관관계 주인

연관관계의 주인이 아닌 곳에서 데이터 삽입시 문제 발생 예시

// 테스트 실패 예시
@DataJpaTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserRepositoryTest {

    @Autowired
    EntityManager em;

    @Autowired
    UserRepository userRepository;

    @Autowired
    KnowledgeRepository knowledgeRepository;

    static Knowledge generateKnowledge(User user, String title, String content) {
        return Knowledge.builder()
                .user(user)
                .title(title)
                .content(content)
                .build();
    }

    @Test
    @DisplayName("user가 등록한 knowledge 조회")
    void findUserKnowledges() {

        // given
        String email = "dev.hyeonic@gmail.com";
        User user = User.builder()
                .email(email)
                .build();

        user.getKnowledges().add(generateKnowledge(user, "지식1", "지식1 내용")); // 주인이 아닌 쪽에서 데이터를 추가
        user.getKnowledges().add(generateKnowledge(user, "지식2", "지식2 내용")); // 주인이 아닌 쪽에서 데이터를 추가

        userRepository.save(user);

        // 영속성 컨텍스트를 비워준다.
        em.flush();
        em.clear();

        // when
        User findUser = userRepository.findById(user.getId()).get();
        List<Knowledge> knowledges = findUser.getKnowledges();

        // then
        assertAll(
                () -> assertEquals(2, knowledges.size()),
                () -> assertEquals(2, knowledgeRepository.findAll().size())
        );
    }
}
berryberrybin commented 1 year ago

해결방안

-문제점 : knowledgeRepository.save(...); 과정에서 user 쪽에도 knowledges에 knowledge를 추가해주어야 함

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Knowledge {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "knowledge_id")
    private Long id;

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

    @Column(length = 20)
    private String title;

    @Column(columnDefinition = "TEXT")
    private String content;

    @Builder
    public Knowledge(User user, String title, String content) {
        this.user = user;
        this.user.getKnowledges().add(this); // User.Knowledges에도 knowledge를 추가해준다.
        this.title = title;
        this.content = content;
    }
}
berryberrybin commented 1 year ago

댓글 구현

@Getter
@Entity
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@SQLDelete(sql = "UPDATE comment SET is_deleted=true WHERE comment_id = ?")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Comment extends DateTimeEntity {

    @Id
    @EqualsAndHashCode.Include
    @GeneratedValue(generator = "UUID")
    @Column(name = "comment_id", columnDefinition = "BINARY(16)")
    @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
    private UUID id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "post_id")
    private Post post;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_Comment_id")
    private Comment parentComment;

    @OneToMany(mappedBy = "parentComment", orphanRemoval = true)
    private List<Comment> childComments = new ArrayList<>();

    @Column
    private String content;

    @Column
    private Boolean isDeleted = false;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "comment", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<CommentLike> commentLikes = new ArrayList<>();

    @Builder
    public Comment(User user, Post post, String content, Comment parentComment) {
        this.user = user;
        this.post = post;
        this.content = content;
        this.parentComment = parentComment;
        if(parentComment != null){
            this.parentComment.getChildComments().add(this);
        }
    }

    public Integer getCommentLikeCount() {
        return commentLikes.size();
    }

    public void addCommentLike(CommentLike commentLike) {
        this.commentLikes.add(commentLike);
    }

}
berryberrybin commented 1 year ago

https://hyeonic.tistory.com/224