데이터베이스 테이블과 Entity의 연관 관계 표현 차이
users 테이블 생성
users 테이블 : 물품 구매를 할 이용자 목록
CREATE TABLE users
(
id bigint not null auto_increment,
name varchar(255),
primary key(id)
);
id를 primary key로 하여 users 테이블이 생성되었다.
product 테이블 생성
product 테이블 : 물품 목록
CREATE TABLE product
(
id bigint not null auto_increment,
name varchar(255),
price float(53) not null,
primary key (id)
);
id를 primary key로 하여 porduct 테이블이 생성되었다.
users와 product 의 관계 생각해보기
1명의 이용자는 여러개의 물품을 주문할 수 있다.
1:N의 관계라고 볼 수 있다.
1개의 물품은 여러명의 이용자들에 의해 구매가 될 수 있다.
이또한 1:N의 관계이다.
그렇다면 이용자와 물품의 관계는
N:N의 관계가 된다.
유저 1명 : 물품 N개 | 1 : N |
유저 N명 : 물품 1개 | N : 1 |
유저 : 물품 | N : N |
데이터 베이스에서의 두 테이블의 연관 관계
데이터 베이스에서
유저 1명이 물품 N개를 주문했다는 것을 표현해 보자.
1. users 테이블에 주문한 물품 저장하기
id | name | product_id |
1 | John | 1 |
2 | Kate | 1 |
3 | John | 2 |
"John"이 1번 물건을 사고 2번 물건을 샀더니
users테이블이 중복이 되었다.
2. product 테이블에 주문한 고객 저장하기
id | name | price | user_id |
1 | 곰인형 | 15000 | 1 |
2 | 곰인형 | 15000 | 2 |
3 | 미미인형 | 17000 | 1 |
"곰인형"을 여러사람이 주문할 때
product 테이블도 불필요한 중복이 발생하였다.
3. product 테이블에서 불필요한 데이터 줄여보기
id | name | price | user_id |
1 | 곰인형 | 15000 | 1,2 |
2 | 미미인형 | 17000 | 1 |
위처럼 데이터를 저장한다면
이용자 1번의 아이디를 조회할 때 2번의 정보도 조회가 되어
많은 문제가 발생할 수 있기 때문에 좋은 방법이 아니다.
4. orders 테이블 만들기
orders 테이블 생성
CREATE TABLE orders
(
id bigint not null auto_increment,
user_id bigint,
product_id bigint,
order_date date,
primary key (id)
);
"user_id"와 "product_id" 를 fk로 가져오기 위해 컬럼을 생성하였고,
"order_date"를 추가했다.
orders table에 fk 부여
ALTER TABLE orders
ADD CONSTRAINT orders_user_fk
FOREIGN KEY (user_id)
REFERENCES users (id);
ALTER TABLE orders
ADD CONSTRAINT orders_product_fk
FOREIGN KEY (product_id)
REFERENCES product (id);
"orders" 테이블에 두개의 foreign key가 추가된 것이 확인 가능하다.
데이터 추가하기
INSERT INTO users (name) VALUES ('John');
INSERT INTO users (name) VALUES ('Kate');
INSERT INTO product (name, price) VALUES ('곰인형', 15000);
INSERT INTO product (name, price) VALUES ('미미인형', 17000);
INSERT INTO product (name, price) VALUES ('콩순이', 13000);
INSERT INTO product (name, price) VALUES ('애나벨', 9000);
INSERT INTO orders (user_id, product_id, order_date) VALUES (1, 1, SYSDATE());
INSERT INTO orders (user_id, product_id, order_date) VALUES (2, 1, SYSDATE());
INSERT INTO orders (user_id, product_id, order_date) VALUES (2, 2, SYSDATE());
INSERT INTO orders (user_id, product_id, order_date) VALUES (1, 4, SYSDATE());
INSERT INTO orders (user_id, product_id, order_date) VALUES (2, 3, SYSDATE());
"John"이 주문한 상품을 users table 기준으로 조회해보기
SELECT u.name AS username, p.name AS productname, o.order_date FROM users u
INNER JOIN orders o on u.id = o.user_id
INNER JOIN product p on p.id = o.product_id
WHERE u.id = 1;
"John"이 주문한 상품을 product table 기준으로 조회해보기
SELECT u.name AS username, p.name AS productname, o.order_date FROM product p
INNER JOIN orders o on p.id = o.product_id
INNER JOIN users u on o.user_id = u.id
WHERE u.id = 1;
데이터베이스에서 테이블간의 관계에서
어떤 테이블을 기준으로 하든 원하는 정보를
JOIN으로 사용하여 조회할 수 있다.
-> 데이터베이스의 테이블 관계에서는 방향의 개념이 없다.
Entity에서의 두 테이블의 연관 관계
N : 1 표현하기
User Entity
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Getter
@Entity
@Table(name = "users")
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "user")
private List<Product> productList = new ArrayList<>();
public User (String name) {
this.name = name;
}
}
"User Entity"에서는
"users table"에 있는
주문자의 이름을 표현하기 위해
private String name;
으로
컬럼과 매칭하기 위해 변수를 선언해주었다.
주문자는 상품을 여러개 주문 할 수 있으므로
private List<Product> productList = new ArrayList<>();
로 표현이 되었다.
Product Entity
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Getter
@NoArgsConstructor
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private double price;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
"Produdct Entity" 에서는
"product table" 에 있는
상품 이름과 가격을 표현하기위해
private String name;
private double price;
로 컬럼과 매칭하기 위하여 변수를 선언하였다.
또한 N : 1을 표현하기 위해
private User user;
로 이용자의 정보도 가지고 있다.
Entity에서 위처럼 표현하는 이유
DB 테이블에서는 이용자 테이블을 기준으로 상품의 정보를 조회할 때
JOIN을 사용하여 바로 조회가 가능하지만
고객 Entity의 입장에서는 상품 Entity의 정보를 가지고 있지 않으면
상품의 정보를 조회할 방법이 없다.
-> Entity 상태에서 다른 Entity를 참조하기 위하여 위처럼 표현한다.
위의 코드는 Product Entitiy와 User Entity가 서로를 참조하고 있다.
이러한 관계를 양방향 관계라고 한다.
단방향 관계 표현해보기
User Entity
package com.practice.practice.entity;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Getter
@Table(name = "users")
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public User(String name) {
this.name = name;
}
}
Product Entity
package com.practice.practice.entity;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Getter
@NoArgsConstructor
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
"Product Entity"에서만 "User"를 참조할 수 있다.
이러한 관계를 단방향 관계 라고 한다.
고객 Entity에서는 상품 Entity에대한 정보가 없기 때문에
상품을 조회할 수 없다.
DB 테이블에서는 연관관계를 FK(외래 키)로 맺을 수 있고,
Entity에서는 상태 Entity를 참조(객체주소)하여 연관 관계를 맺을 수 있다.
-> Entity에서는 방향의 개념이 존재한다.
내용 참고 - 스파르타 코딩클럽 -
'자바 탐구' 카테고리의 다른 글
JPA) Entity의 연관 관계 - @ManyToOne - (0) | 2023.05.03 |
---|---|
JPA) Entity의 연관 관계 - @OneToOne - (0) | 2023.05.02 |
인텔리제이) MySQL 연동하기 (0) | 2023.04.30 |
자바) Program, Process, Thread (0) | 2023.04.27 |
인텔리제이) Entity ERD 확인하기 (0) | 2023.04.27 |