
음식 테이블과 고객 테이블이 N : 1 양방향 관계로 가정 해보겠습니다.
.
{ // 난주엥 설명
saveAll :
.deleteAl : .....
}
/////
@Test
@DisplayName("아보카도 피자 조회")
void test1() {
Food food = foodRepository.findById(2L).orElseThrow(NullPointerException::new);
System.out.println("food.getName() = " + food.getName());
System.out.println("food.getPrice() = " + food.getPrice());
System.out.println("아보카도 피자를 주문한 회원 정보 조회");
System.out.println("food.getUser().getName() = " + food.getUser().getName());
}
food.getName() = 아보카도 피자
food.getPrice() = 50000.0
아보카도 피자를 주문한 회원 정보 조회
food.getUser().getName() = Robbie
이 코드의 문제는 코든 정보 + 유저 정보 까지 가저온다는것.
Hibernate:
select
f1_0.id,
f1_0.name,
f1_0.price,
u1_0.id,
u1_0.name
from
food f1_0
left join
users u1_0
on u1_0.id=f1_0.user_id
where
f1_0.id=?
JPA 에서는 연관 관계가 되어 있는 정보를
바로 가져 올지 vs 필요 할때만 가져올지 정할수 있다. (Fetch Type)
FetchType.LAZY : 지연로딩 (@OneToMany default 가 Lazy)
FetchType.EAGER : 즉시로딩 (@ ManyToOne default 가 EAGER )
test ( EAGER )
@DisplayName("Robbie 고객 조회")
void test2() {
User user = userRepository.findByName("Robbie");
System.out.println("user.getName() = " + user.getName());
System.out.println("Robbie가 주문한 음식 이름 조회");
for (Food food : user.getFoodList()) {
System.out.println(food.getName());
}
}
Hibernate:
/* <criteria> */ select
u1_0.id,
u1_0.name
from
users u1_0
where
u1_0.name=?
user.getName() = Robbie
Robbie가 주문한 음식 이름 조회
Hibernate:
select
ol1_0.user_id,
ol1_0.id,
ol1_0.name,
ol1_0.price
from
food ol1_0
where
ol1_0.user_id=?
고구마 피자
아보카도 피자
후라이드 치킨
User 객체 안에 PK 가 있고 Food 테이블에 조회 해서
퀘리를 만들어서 List 에 가져오는것.
test ( Lazy )
하면
에러가 뜹니다....
영속성 컨텍스트 랑 지연 로딩 :
1 차 캐시 쓰기 - 지연 저장소 - 변경감지 처럼...
지연 로딩 도 영속성 컨텍스트 중 하나 입니다.
지연 로딩 이 된 엔티티의 정보를 조회 하려면. 반드시 영속성 컨텍스트가 존재 해야 합니다.
@Transection 이 적용 되어 야 한다는 뜻. (원래 조회(Select) 할때는 필수 가 아니었지요)
지연 로딩 조회는 @Transection 적용 이 필수 입니다.
영속성 전이 (CaseCadeTest)
유저에 함수 추가
public void addFoodList(Food food) {
this.orderList.add(food);
food.setUser(this);// 외래 키(연관 관계) 설정
}
테스트
@Test
@DisplayName("Robbie 음식 주문")
void test1() {
// 고객 Robbie 가 후라이드 치킨과 양념 치킨을 주문합니다.
User user = new User();
user.setName("Robbie");
// 후라이드 치킨 주문
Food food = new Food();
food.setName("후라이드 치킨");
food.setPrice(15000);
user.addFoodList(food);
Food food2 = new Food();
food2.setName("양념 치킨");
food2.setPrice(20000);
user.addFoodList(food2);
userRepository.save(user);
foodRepository.save(food);
foodRepository.save(food2);
}
Hibernate:
/* insert for
cohttp://m.sparta.jpaadvance.entity.User */insert
into
users (name)
values
(?)
Hibernate:
/* insert for
cohttp://m.sparta.jpaadvance.entity.Food */insert
into
food (name, price, user_id)
values
(?, ?, ?)
Hibernate:
/* insert for
cohttp://m.sparta.jpaadvance.entity.Food */insert
into
food (name, price, user_id)
values
(?, ?, ?)
Robbie가 음식을 주문하기 위해서는 위 처럼 user, food, food2
모두 직접 save() 메서드를 호출하면서 영속화해야합니다.
유저 안에 이미 food list 가 있데....
JPA에서는 이를 간편하게 처리할 수 있는 방법으로 영속성 전이
(CASCADE)의 PERSIST 옵션을 제공합니다.
(FK 있는 SQL delete 했을때 on delete cascade 같은게 있었지요)
영속성 전이란 : 영속 상태의 Entity에서 수행되는 작업들이 연관된 Entity까지 전파되는 상황을 뜻합니다.
CASCADE : PERSIST :
영속정 전의를 하고 싶음 엔티티 @OneToMany 에 CaseCade 라는 옵션이 있다.
User.java
@OneToMany(mappedBy = "user", cascade = CascadeType.PERSIST)
private List<Food> orderList = new ArrayList<>();
테스트
void test2() {
// 고객 Robbie 가 후라이드 치킨과 양념 치킨을 주문합니다.
User user = new User();
user.setName("Robbie");
// 후라이드 치킨 주문
Food food = new Food();
food.setName("후라이드 치킨");
food.setPrice(15000);
user.addFoodList(food);
Food food2 = new Food();
food2.setName("양념 치킨");
food2.setPrice(20000);
user.addFoodList(food2);
userRepository.save(user);
}
food, food2 save() 가 없어도 저장이 됩니다.
Hibernate:
create table food (
id bigint not null auto_increment,
name varchar(255),
price float(53) not null,
user_id bigint,
primary key (id)
) engine=InnoDB
Hibernate:
create table users (
id bigint not null auto_increment,
name varchar(255),
primary key (id)
) engine=InnoDB
Hibernate:
alter table food
add constraint FKonuv85jhrw21c6y3c9cg0ep6o
foreign key (user_id)
references users (id)
삭제 하는 법 :
엔티티에 CASCADE : REMOVE 추가 해줘야 함
영속성 전이 없이는
// 주문한 음식 데이터 삭제
foodRepository.deleteAll(user.getFoodList());
// Robbie 탈퇴
userRepository.delete(user);
두 repo 에서 지워야 했지만.
영속성 전이 를 사용 하면
@Test
@Transactional
@Rollback(value = false)
@DisplayName("영속성 전이 삭제")
void test4() {
// 고객 Robbie 를 조회합니다.
User user = userRepository.findByName("Robbie");
System.out.println("user.getName() = " + user.getName());
// Robbie 가 주문한 음식 조회
for (Food food : user.getFoodList()) {
System.out.println("food.getName() = " + food.getName());
}
// Robbie 탈퇴
userRepository.delete(user);
}
}
userRepository.delete(user); 로 한방에 없엘수 있다.
'Spring' 카테고리의 다른 글
| Spring 숙련 20 (My Select Shop 프로젝트 1) / 상품 검색 API 구현 및 확인 (1) | 2024.01.31 |
|---|---|
| Spring 숙련 19 (고아 엔티티 지우기(Orphan)) () (0) | 2024.01.31 |
| Spring 숙련 17 (1 대 N 관계) (N 대 M 관계) (0) | 2024.01.30 |
| Spring 숙련 16 (1 대 1 관계) (N 대 1 관계) (0) | 2024.01.29 |
| Spring 숙련 15 (Entity 연관 관계) (1) | 2024.01.29 |