다오의 개발일지

TIL-16 JPA Entity 연관관계 N대1 관계 본문

WTIL

TIL-16 JPA Entity 연관관계 N대1 관계

다오__ 2023. 6. 23. 17:34

N대 1 관계

  @ManyToOne 애너테이션은 N대1관계를 맺어주는 역할을 한다.

  음식 Entity와 고객 Entity가 N대1관계라 가정하여 관계를 맺어보자

 

-단방향 관계

 

음식 Entity가 N의 관계로 외래 키의 주인이다.

 

  • 음식
@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;
}
  • 고객
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

 

-양방향 관계

양방향 참조를 위해 고객 Entity에서 Java 컬렉션을 사용하여 음식 Entity를 참조한다.

  • 음식 Entity가 N의 관계로 외래 키의 주인
  • 음식
@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;
}

 

  • 고객
@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();

고객입장에서 음식은 N이기 때문에 Collection으로 담아줘야 한다.

 

 

테스트를 진행해보자.

@SpringBootTest
@Transactional
public class ManyToOneTest {

    @Autowired
    UserRepository userRepository;

    @Autowired
    FoodRepository foodRepository;

    @Test
    @Rollback(value=false)
    @DisplayName("N:1 단방향 테스트")
    void test1(){
        User user = new User();
        user.setName("kys");

        Food food = new Food();
        food.setPrice(15000);
        food.setName("치킨");
        food.setUser(user);

        Food food2 = new Food();
        food2.setPrice(15000);
        food2.setName("불고기피자");
        food2.setUser(user);

        userRepository.save(user);
        foodRepository.save(food);
        foodRepository.save(food2);

    }

    @Test
    @DisplayName("N:1 단방향 조회 테스트")
    void test2(){
        Food food = foodRepository.findById(1L).orElseThrow(NullPointerException::new);
        //단방향은 이런게 안좋다. user입장에서 조회를 못하니깐 user가 주문한 음식들을 한번에 볼수가 없다.

        //단순히 음식입장에서 주문한 고객만을 조회할 수 있을 뿐이다.
        System.out.println("food.getUser().getName() = " + food.getUser().getName());
        System.out.println("food.getName() = " + food.getName());
        System.out.println("food.getPrice() = " + food.getPrice());
    }

    @Test
    @Rollback(value= false)
    @DisplayName("N:1 양방향 테스트")
    void test3(){
        User user = new User();
        user.setName("kys");

        Food food = new Food();
        food.setName("치킨");
        food.setPrice(15000);
        food.setUser(user);

        Food food2 = new Food();
        food2.setName("불고기피자");
        food2.setPrice(23000);
        food2.setUser(user);

        userRepository.save(user);
        foodRepository.save(food);
        foodRepository.save(food2);
    }

    @Test
    @DisplayName("N:1 양방향 조회 테스트 user기준")
    void test4(){
        User user = userRepository.findById(1L).orElseThrow(NullPointerException::new);
        //고객 이름
        System.out.println("user.getName() = " + user.getName());
        //고객잉 주문한 음식 리스트
        List<Food> list =  user.getFoodList();
        for (Food food : list) {
            System.out.println("food.getName() = " + food.getName());
            System.out.println("food.getPrice() = " + food.getPrice());
        }
    }
}

 

 

 

N:1관계 중 N인 음식이 외래키를 가지므로 단방향일 경우 고객의 음식리스트를 볼 수 없다는 단점이있다고 생각이 들었는데.

N:1관계의 경우 양방향으로 서로 조회가 가능하게끔 설계하는것이 편하다고 느꼈다.