[스프링부트JPA] 쇼핑몰 연관관계 맵핑

JEONG SUJIN·2023년 1월 30일
0
  • 연관 관계 매핑의 종류와 엔티티 연관관계 매핑을 설정하는 방법
  • 매핑된 엔티티 조회시 즉시로딩과 지연로딩의 차이점

데이터베이스에서 테이블끼리 외래키를 통해 연관관계를 맺듯이 엔티티끼리 연관 관계를 매핑해서 사용한다

연관관계 매핑 종류

엔티티들은 대부분 다른 엔티티와 연관 관계를 맺고 있다.
JPA에서는 엔티티에 연관관계를 매핑해두고 필요할 때 해당 엔티티와 연관된 엔티티를 사용하여 좀 더 객체지향적으로 프로그래밍 할 수 있다.

  • 일대일 (1:1) : @OneToOne
  • 일대다 (1:N) : @OneToMany
  • 다대일 (N:1) : @ManyToOne
  • 다대다 (N:N) : @ManyToMany

연관관계 방향성

-단방향
-양방향

일대일 단방향 매핑하기

회원엔티티는 앞에서 만들었기 때문에 장바구니(Cart) 엔티티를 만들고 회원 엔티티와 연관관계 매핑을 설정.

Cart.java

  • @OneToOne 어노테이션을 이용해 회원 엔티티와 일대일로 매핑 설정
  • @JoinColumn 어노테이션을 이용해 매핑 할 외래키를 지정. name속성에는 매핑할 외래키의 이름을 설정한다.
    @JoinColumnd의 name을 명시하지 않으면 JPA가 알아서 ID를 찾아서 칼럼명이 원하는 대로 생성되지 않을 수 있기 때문에 직접 지정
import javax.persistence.*;
import lombok.Data;

@Entity
@Table(name="cart")
@Data
public class Cart {
	
	@Id
	@Column(name = "cart_id")
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Long id;
	
	@OneToOne
	@JoinColumn(name="user_id")
	private Users users;
		
}

장바구니 엔티티가 일방적으로 회원 엔티티를 참조

장바구니와 회원은 일대일로 매핑돼 있으며, 장바구니 엔티티가 회원 엔티티를 참조하는 일대일 단방향 매핑이다.

Cart테이블은 user_id를 외래키(foreign key) 가지고 있다.
테이블을 먼저 생성하는 쿼리문이 실행되고 user_id를 foreign key로 지정하는 쿼리문이 실행한다.

실제로 장바구니 Cart엔티티를 조회하면 user_id를 가지고온다.

장바구니 엔티티 조회 테스트하기(즉시로딩)

CartRepository.java

public interface CartRepository extends JpaRepository<Cart, Long> {
}

CartTest.java

package com.shopping.study.entity 패키지에 CartTest생성

em.flush()

  • JPA는 영속성 컨테스트에 데이터를 저장 후 트랜잭션이 끝날때 flush()를 호출하여 데이터베이스에 반영한다. 회원엔티티와 장바구니 엔티티를 영속성 컨텍스트에 저장 후 엔티티 매니저로부터 강제로 flush()를 호출하여 데이베이스에 반영한다.

em.clear()

  • JPA 영속성 컨텍스트로부터 엔티티를 조회 후 영속성 컨텍스트에 엔티티가 없을 경우 데이터베이스를 조회한다. 실제 데이터베이스에서 장바구니 엔티티를 가지고 올 때 회원 엔티티도 같이 가지고 오는지 보기 위해서 영속성 컨텍스트를 비워준다.
package com.shopping.study.entity;

import static org.junit.jupiter.api.Assertions.assertEquals;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;

import com.shopping.study.dto.UsersFormDto;
import com.shopping.study.repository.CartRepository;
import com.shopping.study.repository.UsersRepository;

@SpringBootTest
@Transactional
@TestPropertySource(locations="classpath:application-test.properties")
public class CartTest {
 
	@Autowired
	CartRepository cartRepository;
	
	@Autowired
	UsersRepository usersRepository;
	
	@Autowired
	PasswordEncoder passwordEncoder;
	
	@Autowired
	EntityManager em;
	
	
	public Users createUsers() {
		UsersFormDto usersFormDto = new UsersFormDto();
		
		usersFormDto.setEmail("angela@naver.com");
		usersFormDto.setName("안젤");
		usersFormDto.setAddress("대한민국");
		usersFormDto.setPassword("1234");
		return Users.createUser(usersFormDto, passwordEncoder);
	}
	
	@Test
	@DisplayName("장바구니 회원 엔티티 매핑 테스트 ")
	public void findCartAndUsersTest() {
		Users users = createUsers();
		usersRepository.save(users);
		
		Cart cart = new Cart();
		cart.setUsers(users);
		cartRepository.save(cart);
		
		em.flush();
		em.clear();
		
		
		Cart savedCart = cartRepository.findById(cart.getId()).orElseThrow(EntityNotFoundException::new);
		assertEquals(savedCart.getUsers().getId(), users.getId());

	}
}

테스트 성공후 콘솔창에
cart아래에 users도 같이 들고오는걸 확인할 수 있다.

📍 여기서 잠깐
엔티티를 조회할 때 해당 엔티티와 매핑된 엔티티도 한 번에 조회하는것을 즉시 로딩 이라고 한다.

일대일(OneToOne), 다대일(ManyToOne)로 매핑할 경우 즉시 로딩을 기본 Fetch 전략을 설정한다. Cart.java클래스에서 users엔티티와 일대일 매핑 관계를 맺어줄 때 따로 옵션을 주지 않으면 아래코드와 같이 FetchType.EAGER(즉시 로딩)로 설정하는것과 동일하다.

@OneToOne(fetch = FetchType.EAGER)
profile
기록하기

0개의 댓글