# 댓글 엔티티와 리파지터리(feat. 데이터의 관계)
## 미션
댓글(Comment)을 위한 엔티티와 리파지터리를 만들고, 이를 테스트하시오.
![홍팍-스프링-부트-입문--미션](http://drive.google.com/thumbnail?export=view&sz=w960&id=1eByGImTr7WQofNTgi-Egztbk7gvn7_eb)
## 02:46 댓글 엔티티 구현 - @ManyToOne, @JoinColumn
#### ../entity/Comment
```
package com.example.firstproject.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
@Entity
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "article_id")
private Article article;
@Column
private String nickname;
@Column
private String body;
}
```
## 07:08 더미 데이터 추가
#### ../resources/data.sql
```
-- 15강: article 더미 데이터
-- 17강: article 더미 데이터에서 id 정보를 제거
INSERT INTO article(title, content) VALUES('가가가가', '1111');
INSERT INTO article(title, content) VALUES('나나나나', '2222');
INSERT INTO article(title, content) VALUES('다다다다', '3333');
-- 22강: article 더미 데이터
INSERT INTO article(title, content) VALUES('당신의 인생 영화는?', '댓글 ㄱ');
INSERT INTO article(title, content) VALUES('당신의 소울 푸드는?', '댓글 ㄱㄱ');
INSERT INTO article(title, content) VALUES('당신의 취미는?', '댓글 ㄱㄱㄱ');
-- 22강: comment 더미 데이터
---- 4번 게시글의 댓글들
INSERT INTO comment(article_id, nickname, body) VALUES(4, 'Park', '굳 윌 헌팅');
INSERT INTO comment(article_id, nickname, body) VALUES(4, 'Kim', '아이 엠 샘');
INSERT INTO comment(article_id, nickname, body) VALUES(4, 'Choi', '쇼생크의 탈출');
---- 5번 게시글의 댓글들
INSERT INTO comment(article_id, nickname, body) VALUES(5, 'Park', '치킨');
INSERT INTO comment(article_id, nickname, body) VALUES(5, 'Kim', '샤브샤브');
INSERT INTO comment(article_id, nickname, body) VALUES(5, 'Choi', '초밥');
---- 6번 게시글의 댓글들
INSERT INTO comment(article_id, nickname, body) VALUES(6, 'Park', '조깅');
INSERT INTO comment(article_id, nickname, body) VALUES(6, 'Kim', '유튜브');
INSERT INTO comment(article_id, nickname, body) VALUES(6, 'Choi', '독서');
```
## 12:09 SQL 연습
#### h2 콘솔에서 SQL 연습
```
-- 4번 게시글의 모든 댓글
SELECT
*
FROM
comment
WHERE
article_id = 4
;
-- 닉네임이 Park인 모든 댓글
SELECT
*
FROM
comment
WHERE
nickname = 'Park'
;
```
## 13:41 댓글 리파지터리 구현 - @Query
#### ../repository/CommentRepository
```
package com.example.firstproject.repository;
import com.example.firstproject.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface CommentRepository extends JpaRepository<Comment, Long> {
@Query(value =
"SELECT * " +
"FROM comment " +
"WHERE article_id = :articleId",
nativeQuery = true)
List<Comment> findByArticleId(Long articleId);
List<Comment> findByNickname(String nickname);
}
```
#### ⚠️ articleId를 찾지 못해 에러 발생 시, @Param 어노테이션으로 파라미터 정보 추가
```
@Query(value =
"SELECT * " +
"FROM comment " +
"WHERE article_id = :articleId",
nativeQuery = true)
List<Comment> findByArticleId(@Param("articleId") Long articleId);
```
## 17:28 네이티브 쿼리 - named-native-query, orm.xml
#### ../resources/META-INF/orm.xml
```
<?xml version="1.0" encoding="utf-8" ?>
<entity-mappings xmlns="https://jakarta.ee/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence/orm
https://jakarta.ee/xml/ns/persistence/orm/orm_3_0.xsd"
version="3.0">
<named-native-query
name="Comment.findByNickname"
result-class="com.example.firstproject.entity.Comment">
<query>
<![CDATA[
SELECT
*
FROM
comment
WHERE
nickname = :nickname
]]>
</query>
</named-native-query>
</entity-mappings>
```
## 20:24 리파지터리 테스트
#### ../test/.../repository/CommentRepositoryTest
```
package com.example.firstproject.repository;
import com.example.firstproject.entity.Article;
import com.example.firstproject.entity.Comment;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
class CommentRepositoryTest {
@Autowired
CommentRepository commentRepository;
@Test
void findByArticleId() {
}
@Test
void findByNickname() {
}
}
```
#### ../test/.../repository/CommentRepositoryTest
```
package com.example.firstproject.repository;
import com.example.firstproject.entity.Article;
import com.example.firstproject.entity.Comment;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
class CommentRepositoryTest {
@Autowired
CommentRepository commentRepository;
@Test
@DisplayName("특정 게스글의 모든 댓글 조회")
void findByArticleId() {
/* Case 1: 4번 게시글의 모든 댓글 조회 */
{
// 준비
Long articleId = 4L;
// 수행
List<Comment> comments = commentRepository.findByArticleId(articleId);
// 예상
Article article = new Article(4L, "당신의 인생 영화는?", "댓글 ㄱ");
Comment a = new Comment(1L, article, "Park", "굳 윌 헌팅");
Comment b = new Comment(2L, article, "Kim", "아이 엠 샘");
Comment c = new Comment(3L, article, "Choi", "쇼생크의 탈출");
List<Comment> expected = Arrays.asList(a, b, c);
// 검증
assertEquals(expected.toString(), comments.toString(), "4번 글의 모든 댓글을 출력!");
}
/* Case 2: 1번 게시글의 모든 댓글 조회 */
{
// 준비
Long articleId = 1L;
// 수행
List<Comment> comments = commentRepository.findByArticleId(articleId);
// 예상
Article article = new Article(1L, "가가가가", "1111");
List<Comment> expected = Arrays.asList();
// 검증
assertEquals(expected.toString(), comments.toString(), "1번 글은 댓글이 없음");
}
}
@Test
@DisplayName("특정 닉네임의 모든 댓글 조회")
void findByNickname() {
/* Case 1: "Park"의 모든 댓글 조회 */
{
// 준비
String nickname = "Park";
// 수행
List<Comment> comments = commentRepository.findByNickname(nickname);
// 예상
Comment a = new Comment(1L, new Article(4L, "당신의 인생 영화는?", "댓글 ㄱ"), nickname, "굳 윌 헌팅");
Comment b = new Comment(4L, new Article(5L, "당신의 소울 푸드는?", "댓글 ㄱㄱ"), nickname, "치킨");
Comment c = new Comment(7L, new Article(6L, "당신의 취미는?", "댓글 ㄱㄱㄱ"), nickname, "조깅");
List<Comment> expected = Arrays.asList(a, b, c);
// 검증
assertEquals(expected.toString(), comments.toString(), "Park의 모든 댓글을 출력!");
}
}
}
```
## 🔥 구글링 훈련하기
- 일대다 다대일 관계
- @ManyToOne
- @JoinColumn
- JpaRepository
- @Query
- JPA native query orm xml
- @DataJpaTest @SpringBootTest 비교