Entity 연관 관계

금은체리·2023년 11월 17일
0

Spring

목록 보기
28/49

프로젝트 생성

프로젝트 준비하기

  1. IntelliJ 실행
  2. New Project 클릭
  3. Spring initializr 클릭 후
    • Name: jpa-advance
    • Language: Java
    • Build system: Gradle - Groovy
    • Group:
    • JDK: 17
  4. Next 클릭
  5. Dependencies 추가
    • Spring Data JPA
    • Spring Web
    • MySQL Driver
    • Lombok

프로젝트 설정 추가

  • src > main > resources > application.properties
  • application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/orderapp
spring.datasource.username=root
spring.datasource.password={비밀번호}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true

  • IntelliJ DB 연동
CREATE DATABASE orderapp;
  1. Database 클릭 후, + 버튼 클릭
  2. Data Source > MySQL 클릭
  3. User, Password, Database 정보 추가
  4. 완료!

주문 APP DB table 설계

고객(users) 테이블

idname
1Robbie
2Robbert
create table users
(
    id   bigint not null auto_increment,
    name varchar(255),
    primary key (id)
);

음식(food) 테이블

idnameprice
1후라이드 치킨15000
2양념 치킨20000
3고구마 피자30000
4아보카도 피자50000
create table food
(
    id    bigint not null auto_increment,
    name  varchar(255),
    price float(53) not null,
    primary key (id)
);

DB table간의 연관 관계

연관 관계 고민

  • 고객이 음식을 주문 시, 주문 정보는 어느 테이블에 들어가야 할까?

    • 고객 테이블? 음식 테이블?
    1. 고객 테이블
    • 한명의 고객은 음식을 여러개 주문 가능

      • 고객과 음식은 1대 N 관계
    • 주문한 음식의 정보를 파악하기 위해 food_id 컬럼 추가

    • 고객 테이블에 주문 정보를 넣음

      idnamefood_id
      1Robbie1
      2Robbert1
      3Robbie2
    • Robbie는 후라이드 치킨, 양념 치킨 주문

      • 불필요하게 고객의 이름이 중복되는 문제 발생
    2. 음식 테이블
    • 하나의 음식은 여러명의 고객에게 주문될 수 있음

      • 음식과 고객은 1대 N 관계
    • 주문한 음식의 정보를 파악하기 위해 user_id 컬럼 추가

    • 음식 테이블에 주문 정보를 넣음

      idnamepriceuser_id
      1후라이드 치킨150001
      2후라이드 치킨150002
      3양념 치킨200001
    • 후라이드 치킨을 여러 사람이 주문하게 되었을 때

    • 불칠요하게 음식의 이름이 중복되는 문제 발생

    3. 주문 테이블
    • 주문에 대한 정보를 기록할 orders 테이블 추가

      create table orders
      (
          id         bigint not null auto_increment,
          user_id    bigint,
          food_id    bigint,
          order_date date,
          primary key (id)
      );
    • 주문 테이블을 사용하여 테이블들의 연관 관계 해결

      drop table if exists food;
      drop table if exists users;
      create table users
      (
          id   bigint not null auto_increment,
          name varchar(255),
          primary key (id)
      );
      
      create table food
      (
          id    bigint    not null auto_increment,
          name  varchar(255),
          price float(53) not null,
          primary key (id)
      );
      
      alter table orders
          add constraint orders_user_fk
              foreign key (user_id)
                  references users (id);
      
      alter table orders
          add constraint orders_food_fk
              foreign key (food_id)
                  references food (id);
      
      INSERT INTO users (name) VALUES ('Robbie');
      INSERT INTO users (name) VALUES ('Robbert');
      
      INSERT INTO food (name, price) VALUES ('후라이드 치킨', 15000);
      INSERT INTO food (name, price) VALUES ('양념 치킨', 20000);
      INSERT INTO food (name, price) VALUES ('고구마 피자', 30000);
      INSERT INTO food (name, price) VALUES ('아보카도 피자', 50000);
      
      INSERT INTO orders (user_id, food_id, order_date) VALUES (1, 1, SYSDATE());
      INSERT INTO orders (user_id, food_id, order_date) VALUES (2, 1, SYSDATE());
      INSERT INTO orders (user_id, food_id, order_date) VALUES (2, 2, SYSDATE());
      INSERT INTO orders (user_id, food_id, order_date) VALUES (1, 4, SYSDATE());
      INSERT INTO orders (user_id, food_id, order_date) VALUES (2, 3, SYSDATE());
    • 고객

      idname
      1Robbie
      2Robbert
    • 음식

      idnameprice
      1후라이드 치킨15000
      2양념 치킨20000
      3고구마 피자30000
      4아보카도 피자50000
    • 주문

      iduser_idfood_id주문일
      1112023-01-01
      2212023-01-01
      3222023-01-01
      4132023-01-01
      5232023-01-01
    • 고객 1명은 음식 N개 주문 가능

      • 고객 : 음식 = 1 : N 관계
    • 음식 1개는 고객 N명에게 주문될 수 있음

      • 음식 : 고객 = 1 : N 관계
    • 결론적으로 고객과 음식은 N : M 관계

      • 고객 : 음식 = N : M 관계
    • 이렇듯 N : M 관계인 테이블들의 연관 관계를 해결하기 위해 orders 테이블처럼 중간 테이블 사용 가능

      • 고객 1명은 주문 여러번 가능
        • 고객 : 주문 = 1 : N
      • 음식 1개는 주문 여러번 될 수 있음
        • 음식 : 주문 = 1 : N

DB table간의 방향

  • DB 테이블간의 관계에서 방향의 개념이 존재할까?
    • 방향은 크게 단방향과 양방향으로 나뉨
      • 예를 들어 단방향은 users 테이블에서만 food 테이블을 참조할 수 있을 때
      • 양방향은 users 테이블과 food 테이블이 서로를 참조할 수 있을 때
  • 고객 'Robbie'가 주문한 음식 정보를 users 테이블 기준으로 조회
SELECT u.name as username, f.name as foodname, o.order_date as orderdate
FROM users u
         INNER JOIN orders o on u.id = o.user_id
         INNER JOIN food f on o.food_id = f.id
WHERE o.user_id = 1;
  • food 테이블 기준으로 'Robbie'가 주문한 음식 정보 조회
SELECT u.name as username, f.name as foodname, o.order_date as orderdate
FROM food f
         INNER JOIN orders o on f.id = o.food_id
         INNER JOIN users u on o.user_id = u.id
WHERE o.user_id = 1;
  • DB에서는 어떤 테이블을 기준으로 하든 원하는 정보를 JOIN하여 조회 가능
    • 이처럼 DB 테이블간의 관계에서는 방향의 개념이 존재하지 않음

Entity간의 연관 관계

  • JPA Entity에서는 테이블간의 연관 관계를 어떻게 표현할까?

  • 음식 : 고객 = N : 1

    • 음식
    @Entity
    @Table(name = "food")
    public class Food {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private double price;
    
        @ManyToOne
        @JoinColumn(name = "user_id")
        private User user;
    }
    • 고객
    @Entity
    @Table(name = "users")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
    
        @OneToMany(mappedBy = "user")
        private List<Food> foodList = new ArrayList<>();
    }
    • 한명의 고객은 여러번 주문 가능
      • 이를 Entity에서 여러번 주문 가능함을 표현하기 위해 Java 컬렉션을 사용하여 List<Food> foodList = new ArrayList<>() 로 표현 가능
    • Entity에서 이렇게 표현하는 이유?
      • DB 테이블에서는 고객 테이블 기준으로 음식의 정보를 조회하려고 할 때
        • JOIN을 사용하여 바로 조회가 가능하지만
      • 고객 Entity 입장에서는 음식 Entity의 정보를 가지고 있지 않으면
        • 음식의 정보를 조회할 방법이 없음

  • 단방향 관계는 어떻게 표현될까

    • 음식
    @Entity
    @Table(name = "food")
    public class Food {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private double price;
    
        @ManyToOne
        @JoinColumn(name = "user_id")
        private User user;
    }
    • 고객
    @Entity
    @Table(name = "users")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
    }
    • 음식 Entity에서만 고객 Entity 참조 가능
      • 이러한 관계를 단방향 관계라 칭함
      • 고객 Entity에는 음식 Entity의 정보가 없기 때문에 음식 정보 조회 불가능

  • 정리
    • DB 테이블에서는 테이블 사이의 연관관계를 FK(외래 키)로 맺을 수 있고 방향 상관없이 조회 가능
    • Entity에서는 상대 Entity를 참조하여 Entity 사이의 연관관계 맺을 수 있음
    • 하지만 상대 Entity를 참조하지 않고 있다면 상대 Entity 조회 불가능
    • 따라서 Entity에서는 DB테이블에는 없는 방향의 개념 존재

@Entity와 @Table의 차이점

profile
전 체리 알러지가 있어요!

0개의 댓글