[ JPA ] 5-1. Entity Relations (ERD,  데이터베이스 기준 연관 관계)
백엔드/JPA

[ JPA ] 5-1. Entity Relations (ERD, 데이터베이스 기준 연관 관계)

Reference. 한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online

이전 글

1. ERD

1. ERD 작성하기

2. ERD 사용하는 방법

  1. 왼쪽 메뉴에 Entity Relation 메뉴 선택 Table 선택
  1. 생성 후 테이블명과 컬럼명을 지정
    → 컬럼을 추가할 때는 Ctrl + Enter를 누르면 밑으로 컬럼이 추가 됌
  1. 릴레이션은 두개 이상의 테이블에서 기준이 되는 테이블에서 연결할 테이블로 선택
  1. 릴레이션을 선택하여, 테이블간의 관계를 표시할 수 있음(1:1, 1:N, N:N)

3. ERD 관계선, 기호

1. 관계선의 종류

  • 실선(Identifying): 식별관계
    • 부모테이블의 PK가 자식테이블의 FK/PK가 되는 경우
    • 부모가 있어야 자식이 생기는 경우
  • 점선(Non-Identifying): 비식별관계
    • 부모테이블의 PK가 자식테이블의 일반속성이 되는 경우
    • 부모가 없어도 자식이 생기는 경우

2. 기호의 종류(도형 혹은 식별자)

  • |: 1개 / 실선은(dash) ‘1'을 나타낸다.
  • ∈: 여러개 / 까마귀 발(crow’s foot or Many)은 ‘다수' 혹은 '그 이상'을 나타낸다.
  • ○: 0개 / 고리(ring or Optional)은 ‘0'을 나타낸다.
  • Type1(실선과 실선): 정확히 1 (하나의 A는 하나의 B로 이어져 있다.)
  • Type2(까마귀발): 여러개 (하나의 A는 여러개의 B로 구성되어 있다.)
  • Type3(실선과 까마귀발): 1개 이상 (하나의 A는 하나 이상의 B로 구성되어 있다.)
  • Type4(고리와 실선): 0 혹은 1 (하나의 A는 하나 이하의 B로 구성되어 있다.)
  • Type5(고리와 까마귀발): 0개 이상 (하나의 A는 0또는 하나 이상의 B로 구성되 있다.)

 

* 출처:

https://eyecandyzero.tistory.com/246

2. 데이터베이스 기준 연관 관계

* 속성 설정

  • Primitive type, Reference Type의 차이 : null을 허용할지 안할지
    • Primitive type: Null이 존재하지 않음
      boolean, byte, int, long, float, double
    • Reference Type: Null이 존재
      Integer, Array, Float, Class
Hibernate: 
    create table book_review_info (
       id bigint not null,
        created_at timestamp,
        updated_at timestamp,
        average_review_score float not null, //primitive type / not null
        book_id bigint,
        review_count integer not null, //primitive type / not null
        primary key (id)
    )

 

1. 데이터베이스 기준 연관 관계 (key값을 통한 쿼리)

1. 연관 쿼리 가져오기 (오류 발생)

  • Entity의 ID @GeneratedValue의 default는 Auto(H2:SEQUENCE) 저장할 때 문제가 발생
    • call next value for hibernate_sequence를 이용함으로, 테이블이 달라도 id가 증가
    • book_review_info 테이블의 id 값이 7이 되어 오류 발생(데이터는 1개)
@Test
void crudTest2(){
    Book book = new Book();
    book.setName("JPA 책");
    book.setAuthorId(1L);
    book.setPublisherId(1L);

    bookRepository.save(book);
    System.out.println(">>> " + book);

    BookReviewInfo bookReviewInfo = new BookReviewInfo();
    bookReviewInfo.setBookId(1L);
    bookReviewInfo.setAverageReviewScore(4.5f);
    bookReviewInfo.setReviewCount(2);

    bookReviewInfoRepository.save(bookReviewInfo);
    System.out.println(">>> " + bookReviewInfoRepository.findAll());

		//키 값을 통해 연관테이블 조회 (데이터베이스 기준)
		Book result = bookRepository.findById(
            bookReviewInfoRepository
                    .findById(1L)
                    .orElseThrow(RuntimeException::new)
                    .getBookId()
    ).orElseThrow(RuntimeException::new);

    System.out.println(">>>" + result);
}
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        book
        (created_at, updated_at, author_id, category, name, publisher_id, id) 
    values
        (?, ?, ?, ?, ?, ?, ?)

>>> Book(super=BaseEntity(createdAt=2021-07-25T08:45:57.884311400, updatedAt=2021-07-25T08:45:57.884311400), id=6, name=JPA 책, category=null, authorId=1, publisherId=1)
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        book_review_info
        (created_at, updated_at, average_review_score, book_id, review_count, id) 
    values
        (?, ?, ?, ?, ?, ?)

>>> [BookReviewInfo(super=BaseEntity(createdAt=2021-07-25T08:45:58.032296, updatedAt=2021-07-25T08:45:58.032296), id=7, bookId=1, averageReviewScore=4.5, reviewCount=2)]

2. 연관 쿼리 가져오기 위해 수정

  • Entity의 ID @GeneratedValue 전략을 IDENTITY로 수정
    • @GeneratedValue(strategy = GenerationType.IDENTITY)
    • IDENTITY로 변경하면 각 테이블에 ID에 자동증가 (id값을 공통으로 관리 X)
data.sql 수정

→ 기존에 기초데이터로 sequence사용, IDENTITY로 바꾸면서 사용 안함. 주석안하면 에러발생

-- call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (1, 'martin', 'martin@fastcampus.com', now(), now());
Book.java
public class Book extends BaseEntity{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
		
		...
}
변경된 결과
//DDL 변경됌
Hibernate: 
    create table book (
       id bigint generated by default as identity,
        created_at timestamp,
        updated_at timestamp,
        author_id bigint,
        category varchar(255),
        name varchar(255),
        publisher_id bigint,
        primary key (id)
    )

//결과값: ID값이 1로 변경됌, 테스트 코드 성공
>>> Book(super=BaseEntity(createdAt=2021-07-25T08:57:27.172218200, updatedAt=2021-07-25T08:57:27.172218200), id=1, name=JPA 책, category=null, authorId=1, publisherId=1)