
Post : 게시글
Reply : 댓 글
post가 주인이지만 reply안에 있는 private Post post; 로 접근하는 게 좋다.
일 대 다
1 > N
post 테이블에
@OnetoMany
@JoinColum(name = "POST_ID")
조인 컬럼 안 쓰면 하나의 테이블이 더 생긴다,
private List<Reply> replies = new ArrayList <>();
reply를 칼럼으로 인식하지 말고 연관 관계로 인식해라
@OnetoMany 쓸 때는 조인 칼럼도 같이 써서 fk의 이름도 정해주는 게 좋다.
이렇게 일대다로 연결을 해봤다.
디비에서 조회
SELECT * FROM POST;
SELECT * FROM REPLY;
Post에 Reply Id 가 있는 게 아니라
Reply에 Post Id 가 있는 것임
그러면 접근할 때 Repyl에서 Post로 접근하는 게 RDB에서도 맞는 방향이다.(다 대 일)
지금은 일 대 다 이기 때문에
단위 테스트를 통해 일 대 다의 불편함 알아보기
post를 등록하기 전 포스트 안에 있는 리플라이를 등록하면서 같이 persist를 하면 좋겠지만 그렇게 안된다.
영속 상태가 되어 야기 때문에 Reply부터 등록을 해줘야 한다. 그래야 감지를 한다.
r1.setContent("내용");
r2.setContent("내용");
rdao.save(r1);
rdao.save(r2);
post.ser title("제목");
post.set content("내용");
postdao.save(post);
디비에서 확인해 보면 post는 문제가 없는데
reply애서 post Id에 정보가 없다.
그래서 중간에 Post에게 reply 정보를 주기 위해
post.getReplies(). add(r1);
post.getReplies(). add(r2);
를 해줘서 알려준다.
전과는 다르게 update 쿼리가 나간다
이제 정확하게 post Id가 된다.
생각이 든다. 이렇게 reply에게 어떤 포스트인지 알려줘야 하나 귀찮게
그냥 처음부터 알고 있으면 업데이트 쿼리도 안 써도 되지 않을까.
그래서 이제는 일대다가 아닌 다대일로 해보려고 한다,
이제 reply에 post를 만들어준다. (기존 post에 LIST REPLY 주석)
@ManyToOne
@JoinColum
private Post post
근데 여기서 다대일로 조인칼럼을 post Id를 해주면 전에랑 관계 구조 자체는 비슷할 거다.
다시 단위 테스트로 간다.
이제는 reply를 만들 때마다 포스트를 넣어줘야 한다.
post.setpostTitle("제목");
post.setpostContent("내용");
poDao.save(post);
r1.set("");
r1.setPost(post);
이렇게 reply에게 너는 어떤 Post의 reply라고 지정을 해준다.
이렇게 게시글을 작성하고 댓글을 작성할 때 게시글의 정보를 넘겨주고
댓글을 저장하면 게시글의 정보를 들고 저장이 되지 않을까
쿼리를 보면
update쿼리가 없다 덜 나갔다.
이처럼 다대일로 하는 게 더 편하다 쿼리도 덜 나간다.
다시 일 대 다로 돌아오자
조회를 해보자
postDao.findById(1L). map(Post::toString). ifpresent(log::info);
이때 쿼리를 보면 post selecte 이되고선 reply에 대한 모든 것이 조회가 된다 .
연관관계라서. 조회할 떄 연관된 댓글도 들고 와줘서 편하다.
지금은 괜찮다. 근데 테이블이 많아질 때 나는 게시글만 조회하고 싶을 때 이처럼 게시글에 연관된
모든 테이블의 칼럼이 조회가 될 거다 불필요한 쿼리들,
그래서 이런 거를 설정을 해주면 된다. 그러면 Post를 조회해도 Post만 조회되고, Post에 reply를
수정하거나 다른 작업을 하려고 할 때 그때 reply가 select 쿼리가 나가게 된다.
유동적으로 할 수 있음.
@OneToMany 에 fetch라는 설정이 있다. default가 Lazy이다.
Lazy는 게으르다. 뭐든 쿼리를 날려주지 않는 친구다. 사용할 때 날려준다.
그럼 위에서 default가 Lazy인데 왜 모든 쿼리가 나갔을까 우린 toString을 사용했기 때문.
toString에 getReplies가 있기 때문에 모든 쿼리가 나간 것이다.
다시 toString을 빼면 post에 관한 쿼리만 나가게 된다,.
postDao.findById(1L). ifPresent(post -> log.info(post.getPostCon())));
Lazy반대는 Eager라는 게 있다. 이것은 연결된 객체에 관한 모든 쿼리를 다 날린다.
이제 다대일 방식으로 조회해 보자 여기서 리플라이를 조회했을 때 과연 해당 게시글까지 정보를 받아올 수
있을지 의문이다.
replyDAO.finbyId(2L). ifPresent(eply -> log.info(rply.getRplyConten()));
다대일은 manytoOne이다 이는 디폴트가 eager라서 쿼리가 join이 돼서 나왔다.
lazy로 바꿔서 다시 조회해 보면 댓글에 관한 내용만 나오게 된다.
쿼리를 내가 날리는 게 아니라 JPA가 해주기 때문에 성능적인 부분을 생각을 안 할 수가 없다.
다시 일 대다로 돌아온다
전체 조회를 해보자
log.info(postDao.findAll(). stream(). map.(Post::getTitel). forEach(log::info);
@@~~~~61번째 포스트를 통해서 reply 조회해 보기
수정을 해보자
final Optional found = postDAo.findById(1L);
if(sadasd)
@! 3!#@!@
@#@32
이제 다대일로 하자
댓글로 게시글을 수정해 보기
replyDao.findBy(2L). ifpresent(reply -> reply.getPost(). setPostTitle("PostupdateTitle"));
그래프 알고리즘이랑 유사함
여기까지가 업데이트
마지막 삭제
게시글부터 삭제해 보자
현 관계 : reply 안에 Post 객체가 있는 @ManyToOne 관계이다.
이때 리플라이로 포스트를 가져와야 영속 상태가 돼 삭제를 할 수 있다.
repltDao.findById(2L). ifPresent(rp -> postDao.delete(rp.getPost())));
(댓글로 게시글 삭제해 보기 가능할까?)
오류 내용
select 쿼리는 잘 나갔는데 delete쿼리가 나가면서 오류 발생
violated : child record found(다른 자식이 참조 중이다) 쿼리에서의 cascade를 해주는 이유
이제 반대 방향 일대 다로(@OneToMany)
게시글하나를 가져와 해당 게시글의 댓글을 전부 삭제해보려 한다.
postDAO.findById(1L). ifPresent(po -> po.getRplies(). forEach(replyDAO::delete));
성공
부모를 삭제하면 참조 중인 자식을 다 날려버리는 on delete cascade JPA에도 있다고 한다.
시험해 보기 위해서
다대일로
게시글에 댓글을 추가한다.
삭제 테스트
postDAO.findById(1L). ifPresent(postDAO:delete); 게시글을 지웠을 때 해당 댓글들이 다 삭제가 될까?
역시나 오류 자식에서 참조 중인 애들이 있다고 온다 이걸 가능하게 해 보자
Reply에서
@ManyToOne(fetch ~~,CasecadeType = remove)
이것은 정확이 표현하면 영속 상태를 전이하는 것이다
내가 삭제되면 나랑 관련된 애들을 모두 삭제한다.
repltDao.findById(2L). ifPresent(rp -> postDao.delete(rp.getPost())));
다 오류 난다.
다대일 쪽에서는 케스케드리무블는 어울리지 않는다.
일대다 쪽으로 케스케드 리무브를 써본다
이제 게시글이 삭제가 되면 참조 중인 자식인 댓글이 함께 삭제되는지 테스트해 보자
postDAO.findById(1L). ifPresent(postDAO:delete);
성공 참조 중인 댓글도 모두 삭제가 됐다.
이때 쿼리를 잘 보면 그냥 selcte 다음 deletye가 아니라 조회를 하고 fk값을 null로 바꿔주고 delete가 실행된다.,
추가적으로 cascade 외에 persist도 있다.
처음 에는 insert를 미리 해주고 insert 된 거를 넣어줬다면
이제는 set메서드 변화감지만 해주고 Post를 등록만 하면 연관된 setReply해준 애들 까지도 같이 persist가 된다.
'Spring Boot' 카테고리의 다른 글
| JPA Project 근황 (1) | 2023.08.25 |
|---|---|
| Get, Post, Redirect (1) | 2023.05.02 |
| 타임리프(Timeleaf) (2) | 2023.05.01 |
| MVC 2 (1) | 2023.05.01 |
| Spring 의존성 주입 (0) | 2023.04.30 |