[부트캠프] TIL - Entitiy간 연관관계
엔티티간의 조회에서 방향이란
A와 B 엔티티가 있을때 양방향은 A에서 B를 참조할 수 있고, 반대로 B에서도 A를 참조할 수도 있다는것.
N : 1 - Food가 참조할 상대방 User가 멤버변수로 존재함. 따라서 참조가 가능
@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;
}
반대로 1 : M에서 - 하나의 User가 여러 개의 Food와 연관될 수 있음, 따라서 List형식의 Food 값들을 가짐
@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<>();
}
이렇게 표현하는이유는 DB에서는 Join을 사용하여 상대방에 대한 정보를 조회가 가능하지만, Java 엔티티에서는
상대방의 정보를 가지고 있지 않으면 조회가 불가능하기 때문,
따라서 DB 테이블에는 컬럼으로 들어가지 않지만, Entity 상태에 따른 다른 Entity를 참조하기 위해 이런방법을 사용함.
- DB 테이블에서는 테이블 사이의 연관관계를 FK(외래 키)로 맺을 수 있고 방향 상관없이 조회가 가능합니다.
- Entity에서는 상대 Entity를 참조하여 Entity 사이의 연관관계를 맺을 수 있습니다.
- 하지만 상대 Entity를 참조하지 않고 있다면 상대 Entity를 조회할 수 있는 방법이 없습니다.
- 따라서 Entity에서는 DB 테이블에는 없는 방향의 개념이 존재합니다.
위와같은 관계를 양방향 관계라고 하며 N : M 즉, 다대다 관계라고 합니다. (하지만 실제로는 다대다 관계는 쓰지않고 ManyToOne 만을 사용한다고 하는데 해당 방법은 이후에 나옵니다).
가장중요한건 N : 1 - @ManyToOne
ManyToMany 관계를 풀어낼때 중간 테이블을 생성한 뒤 중간테이블과 양쪽의 테이블간에 맺는관계가 ManyToOne
그리고 지연로딩
Jpa는 연관관계가 설정된 Entity의 정보를 바로 가져올지, 필요할 때 가져올지 정할 수 있습니다.
Fetch Type 이라고 부릅니다. 2가지가 있고.
LAZY -> 지연로딩으로 필요한 시점에 정보를 가져옵니다.
EAGER -> 즉시로딩으로 조회시 연관된 엔티티의 정보 모두를 가져옵니다.
기본적으로 @ManyToOne 어노테이션은 FetchType 이 Eager로 설정되어있습니다.
이해하기 쉽도록 설명하면, 어노테이션의 뒤에 Many가 붙었다면 설정된 필드가 자바 컬렉션 타입입니다,
여러개의 연관데이터가 들어오기 때문에, 따라서 효율적인 조회를 위해 기본타입이 LAZY로 설정되어있습니다.
반대로 어노테이션의 뒤가 One일 경우는 연관된 엔티티의 정보가 하나이기때문에 즉시 정보를 가져와도 무리가 없어서
EAGER가 기본으로 설정되어있습니다.
지연로딩도 영속성 컨텍스트의 기능 중 하나로 지연로딩된 Entity의 정보를 조회하려면 트랜잭션이 적용되어있어야함.
영속성 전이
@Entity
@Getter
@Setter
@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<>();
public void addFoodList(Food food) {
this.foodList.add(food);
food.setUser(this);// 외래 키(연관 관계) 설정
}
}
이렇게 설정된 User 엔티티가 Food를 주문한다면
userRepository.save(user);
foodRepository.save(food);
foodRepository.save(food2);
직접 user와 food 들을 각각의 Repository를 불러서 저장해야합니다,
이것을 영속성 전이를 사용하여 간단하게 처리가가능하며, 영속성 전이랑 영속 상태의 Entity에서 수행되는 작업들이
연관된 Entity까지 전파되는상황.
영속성 전이를 사용하여 연관된 엔티티까지 자동으로 저장하려면 자동으로 저장하려고 하는 연관된 엔티에
추가했던 연관관계 어노테이션에 cascade = CascadeType.PERSIST를 설정합니다.