관계형 데이터베이스는 테이블끼리 관계를 맺을 수 있다.
관계는 논리적으로 연관이 있는 두 테이블 사이의 연결을 설정한다.
이는 테이블 구조를 정제하고 중복 데이터를 최소화하는 것을 도와준다.
@OneToOne
: 1 대 1 관계를 맺어주는 역할👀 외래키(FK)의 주인(Owner)
- FK 주인만이 FK를 등록, 수정, 삭제할 수 있으며, 주인이 아닌 쪽은 오직 FK를 읽기만 가능!
- Entity에서 FK의 주인은 일반적으로 N(다)의 관계인 Entity 이지만 1:1 관계에서는 FK의 주인을 직접 지정해야함
@JoinColumn()
: FK 속성 설정// 음식(FK 주인)
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToOne // 1:1 지정
@JoinColumn(name = "user_id") // FK 지정
private User user;
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
🤔 @JoinColumn() 생략가능하지만 꼭 설정해주자.
- 1:N 관계에서 FK의 주인 Entity가 @JoinColumn() 애너테이션을 생략한다면 JPA가 FK를 저장할 컬럼을 파악할 수가 없어서 의도하지 않은 중간 테이블이 생성된다.
- 양방향 관계에서 mappedBy 옵션을 생략할 경우 JPA가 FK의 주인 Entity를 파악할 수가 없어 의도하지 않은 중간 테이블이 생성되기 때문에 반드시 설정해주는게 좋다.
// 음식(FK 주인)
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToOne // 1:1 지정
@JoinColumn(name = "user_id") // FK 지정
private User user; // 요 user가
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(mappedBy = "user") // 이 user다
private Food food;
}
@ManyToOne
: N 대 1 관계를 맺어주는 역할// 음식(FK 주인)
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToOne // N:1 지정
@JoinColumn(name = "user_id") // FK 지정
private User user;
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
// 음식(FK 주인)
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToOne // N:1 지정
@JoinColumn(name = "user_id") // FK 지정
private User user; // 요 user가
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "user") // 이 user다
private List<Food> foodList = new ArrayList<>();
}
@OneToMany
:1 대 N 관계를 맺어주는 역할// 음식(FK 주인)
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToMany // 1:N 지정
@JoinColumn(name = "food_id") // FK 지정
private List<User> userList = new ArrayList<>();
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "food_id", insertable = false, updatable = false)
private Food food;
}
@ManyToMany
: N 대 M 관계를 맺어주는 역할// 음식(FK 주인)
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToMany // N:M 지정
@JoinTable(name = "orders", // 중간 테이블 생성
joinColumns = @JoinColumn(name = "food_id"), // 현재 위치인 Food Entity 에서 중간 테이블로 조인할 컬럼 설정
inverseJoinColumns = @JoinColumn(name = "user_id")) // 반대 위치인 User Entity 에서 중간 테이블로 조인할 컬럼 설정
private List<User> userList = new ArrayList<>();
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
🚨 생성되는 중간 테이블에는 PK가 없어서 컨트롤하기 어렵기 때문에 추후에 중간 테이블의 변경이 발생할 경우 문제가 발생할 가능성이 있다.
// 음식(FK 주인)
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToMany // N:M 지정
@JoinTable(name = "orders", // 중간 테이블 생성
joinColumns = @JoinColumn(name = "food_id"), // 현재 위치인 Food Entity 에서 중간 테이블로 조인할 컬럼 설정
inverseJoinColumns = @JoinColumn(name = "user_id")) // 반대 위치인 User Entity 에서 중간 테이블로 조인할 컬럼 설정
private List<User> userList = new ArrayList<>(); // 요 userList가
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "userList") // 이 userList다
private List<Food> foodList = new ArrayList<>();
}
// 음식
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToMany(mappedBy = "food")
private List<Order> orderList = new ArrayList<>();
}
// 고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "user")
private List<Order> orderList = new ArrayList<>();
}
// 주문
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "food_id")
private Food food;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}