220419~220420 TIL (SpringDataJdbc oneToMany)

Minseok-Choi·2022년 4월 20일
0

TIL

목록 보기
2/11

학습자료

호눅스의 깃헙코드

학습계기

  • 반찬 프로젝트를 진행하면서 간단하게 테이블을 정의했다.
  • 하나의 dish와 image 테이블은 1:N 관계를 맺는다.
  • 1:N 관계를 가졌을때, 하나의 dish와 해당하는 dish의 id를 가지는 모든 image를 하나의 객체로 만들 수는 없을까? 여러번의 쿼리를 보내서 조합하는 방법이 아닌 join으로는 해결할 수 없을까?
  • 이 생각이 거의 이틀 가까이 삽질을 하게 했다. 그리고 이러한 고민에 대해서는 역시나 멋진 선배 개발자들은 기술을 다 마련해놓으셨고, 우리는 그 기술의 사용법과 원리를 공부하면 되는 것이었다.
  • 학습자료를 미리 봤다면?, Spring data Jdbc에 대한 기본 공부를 조금했더라면? Jpa를 미리 공부했다면? 아쉽다.

SpringDataJdbc oneToMany

  • 예제 코드는 article과 comment, 게시글과 댓글은 1:N 관계이다.
create table if not exists article
(
    id       bigint primary key auto_increment,
    author   varchar(50)
);

create table if not exists comment
(
    id      bigint primary key auto_increment,
    contents varchar(255),
    // foreign key를 해당하는 table명으로 하는 것이 default이다.
    article bigint references article(id)
);
  • Article 객체
public class Article {
    @Id
    private Long id;
    private String author;
    // article의 id를 가지는 comment들을 가져와 저장할 수 있도록 하는 set
    private Set<Comment> comments;

    public Article(String author, Set<Comment> comments) {
        this.author = author;
        this.comments = comments;
    }

    public Long getId() {
        return id;
    }

    public String getAuthor() {
        return author;
    }

    public Set<Comment> getComments() {
        return comments;
    }

    @Override
    public String toString() {
        return "Article{" +
                "id=" + id +
                ", author='" + author + '\'' +
                ", comments=" + comments +
                '}';
    }
//CrudRepository를 활용
@Repository
public interface ArticleRepository extends CrudRepository<Article, Long> {
}
  • Comment 객체
  • foreign key 정보는 가지고 있지않다.
public class Comment {
    @Id
    private Long id;
    private String contents;

    public Comment(String contents) {
        this.contents = contents;
    }

    public String getContents() {
        return contents;
    }

    @Override
    public String toString() {
        return "Comment{" +
                "id=" + id +
                ", contents='" + contents + '\'' +
                '}';
    }

set이 아닌 List나 Map을 활용하려면?

  • many에 해당하는 table에 _key라는 컬럼이 필요하다. 인덱스 혹은 key에 해당하는 정보를 담기 위한 것 같다.
// article의 의미를 더 명확하게 전달하기 위해서 article_id로 컬럼 네이밍 변경
// list활용을 위한 column article_key
create table if not exists comment
(
    id          bigint primary key auto_increment,
    contents    varchar(255),
    article_id   bigint references article(id),
    article_key int
);
 // list를 활용하는 버전
  public class Article {
    @Id
    private Long id;
    private String author;
    // column 네이밍 설정을 위한 어노테이션, 왜인지는 모르겠으나 소문자로했을때 DbActionExecutionException 발생했다.
    @MappedCollection(idColumn = "ARTICLE_ID")
    private List<Comment> comments;

테스트를 해보면

  • 객체로 저장을 하고, 찾아올때도 comment도 다 찾아서 list 타입의 comment로 잘 넣어준다.
  • 아마 내부적으로 join을 하는 쿼리와 중복되는 raw들에 대해서 맵핑하는 것으로 추측한다.
@DataJdbcTest
class ArticleRepositoryTest {

    @Autowired
    ArticleRepository articleRepository;

    @Test
    void save_find_Test() {
        List<Comment> comments = List.of(new Comment("123"), new Comment("321"));
        Article ron2Article = new Article("ron2", comments);
        Article saved = articleRepository.save(ron2Article);
        Article article = articleRepository.findById(1L).orElseThrow();

        assertThat(article.getComments()).hasSize(2);
        assertThat(article.getComments()).contains(new Comment("123"));
        assertThat(article.getComments()).contains(new Comment("321"));
		// 테스트를 위해서 Coment 객체의 equals 메서드를 contents만 같은지 확인하도록 overriding 했습니다.
    }

TODO

  • 내부로직과 원리에 대해서 아직은 추측만을 하고 있다.
  • 또한 OneToOne ,ManyToMany, Embedded와 관련한 사용법에 대해서 아직 정리하지 못했다.
  • 공식문서를 훑어보면서 키워드에 대해서도 알아보고, Jpa와 흡사한 부분이 많으니 얼른 jpa에도 입문해야겠다.
profile
차곡차곡

2개의 댓글

comment-user-thumbnail
2022년 4월 20일

내일 기대하겠음니다 론이

답글 달기
comment-user-thumbnail
2022년 4월 20일

잘읽고갑니다 론이 👍

답글 달기