CRUD 실습

JPA와 Entity, DB 스키마 테스트하기 [탐구/기록]

rexondex 2024. 9. 30. 18:02

현재 상황은 물리적 스키마가 불안정하다는 것과

JPA Repository 가 동작하는 구조를 잘 모르고 있다는 점,

그리고 Entity 클래스와 DTO 클래스의 활용에 있어서 혼동하고 있었습니다.​​

현재 POST 테이블에 저장된 레코드들

 

현재 데이터베이스의 POST 테이블은 이렇게 정의되어 있습니다.

-- POST_ID 게시물 고유 ID ( 1씩 증가하는 순차 시퀀스 )

-- POST_TITLE 게시물 제목

-- POST_CONTENT 게시물 내용

-- MEMBER_NAME 작성자 닉네임

-- TAG_NAME 태그 이름

-- CREATED_AT 생성일자

-- UPDATED_AT 수정일자

정규화 규칙을 위반한 상태입니다.

MEMBER_NAME 과

TAG_NAME 으로 인해

함수종속이 없어야 함을 해결하지 못했습니다.

JPA Repository 인터페이스를 다루는 것이 미숙해서 고민하다 보니 스키마를 변형시켰습니다.

하나의 게시물은 여러개의 태그를 가질 수 있고, 하나의 태그는 여러개의 게시물을 가질 수 있습니다.

다대다 표현관계를 JPA Repository로 구현하려 하였습니다.

현재 렌더링된 HTML

 

실행된 어플리케이션에서는

 

-- POST_TITLE

-- POST_CONTENT

-- MEMBER_NAME

-- TAG_NAME

 

이 요소와 속성들을 확인해볼 수 있으며

아직 추가되지 않은 컬럼 FAVORITE( '좋아요' ) 또한 필요합니다.

JPA Repository를 처음으로 다루면서 어려웠던 점은 물리적 스키마와 제약조건이나 테이블, 관계설정이 정확히 일치하지 않을 수 있었다는 점입니다.

실제로 물리적 스키마에 없는 테이블이나 칼럼이어도, JPA 리포지토리 상에서 테이블 간의 일대다, 다대다 연관관계(@OneToMany, @ManyToOne 등)를 통해 데이터를 읽어내는 동작을 수행하는 걸 확인할 수 있었습니다.

 

제가 직접 필요한 값을 명시하거나 매핑하지 않아도 어느정도 작동하고 있었습니다.

Entity 클래스와 Controller, 그리고 JpaRepository 인터페이스를 상속하는 PostsRepository를 변형하지 않은 채로 타임리프가 적용된 html에서 이전엔 잘 작동했으나 다른 클래스의 변경 없이

타임리프참조식 th:text="${}" 의 내용을 변경하는 것만으로 자체적으로 SQL을 만들어 실행한 후 "일치하는 테이블과 열을 찾을 수 없다"는 오류를 확인할 수 있었습니다.

스키마와 충돌이 있을 경우에는 "physical" 키워드가 포함된 오류를 뱉어냄을 확인할 수 있었습니다.

해결하지 못한 점은 @OneToMany @ManyToOne 을 통해 관계 설정을 할때

( 테이블 / 연관관계설정 / 테이블 ) 의 관계로 중간 테이블을 논리적으로 설정하였으나

직접 접근하고 있는 테이블이 아닌 논리적으로 설정된 @JoinColumn 이나 @JoinTable 에 대해

어떻게 타임리프 표현식으로 참조할 수 있을까? 를 해결하지 못했습니다.

이를 해결하기 위해서는 Controller 레이어에서 Entity 객체를 가져온 후에, Entity 객체에서 게시물을 구성하기 위해 필요한 칼럼을 얻어내어(get) DTO 클래스에 쓰기(set) 하여 필요한 정보들로 구성된 DTO 클래스

Model 객체에 담아 View로 반환하는 것이 합리적인 방법이라고 생각했습니다.

Entity 클래스는 DB로부터 데이터를 CRUD 하기 위한 객체로,

DTO 클래스는 View 계층에서 표현되어야할 게시물의 정보를 가진 객체로 활용되어야 할 것입니다.​​

@Entity
public class Post {
    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "post")
    private List<PostTag> postTags = new ArrayList<>();
}

@Entity
public class Tag {
    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "tag")
    private List<PostTag> postTags = new ArrayList<>();
}

@Entity
public class PostTag {
    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    private Post post;

    @ManyToOne
    private Tag tag;
}

 

다대다 관계를 위한 연결고리테이블을 이렇게 표현해보았습니다.

관계 설정이 제대로 되어 있다면, 스프링부트 환경 안에서 데이터를 제대로 읽어내는지 테스트해볼 수 있을 것이고,

스프링부트 환경에서 관계 설정된 테이블 간의 데이터를 읽어내는 데에 문제가 없다면, 데이터베이스에서 함수종속을 제거하는 것이 목표입니다.