본문 바로가기
JPA

[JPA] Entity 연관 관계

by 2nyong 2023. 4. 28.

목차


    연관 관계

    연관관계란 두 도메인(객체, 테이블) 이 서로 논리적인 의미를 갖고 양쪽을 참조하는 관계를 의미합니다.

    DB에서 테이블들이 연관 관계를 맺는 방법객체 지향 프로그램인 자바에서 객체(Entity)들이 연관 관계를 맺는 방법에 차이가 있습니다.

    이 차이를 해소하여 테이블을 객체로 다룰 수 있도록 해주는 기술이 ORM이며, 자바 진영의 ORM 기술 표준 명세가 JPA입니다.


    - 주문 APP DB 테이블 설계

    DB 테이블의 연관관계와 Entity 간의 연관관계의 차이점을 설명하기 위해 주문 애플리케이션의 DB 테이블 설계를 가정하였습니다.

    • 고객 (users) 테이블
    • 주문 (orders) 테이블
    • 음식 (food) 테이블

    주문 APP DB 설계도


    - DB 테이블 간의 방향

    DB 테이블 간의 방향에서 방향은 크게 단방향양방향을 떠올릴 수 있습니다.

    예를 들어 단방향은 users 테이블에서 food 테이블을 참조할 수 있을 때를 의미하며,

    반대로 양방향은 users 테이블과 food 테이블이 서로참조할 수 있을 때를 의미합니다.

     

    • users 테이블에서 id가 1인 고객이 주문한 음식 정보를 users 테이블 기준으로 조회
    SELECT u.name as username, f.name as foodname, o.order_date as orderdate FROM users u
        INNER JOIN orders o on u.id = o.user_id
        INNER JOIN food f on o.food_id = f.id WHERE u.id = 1;

     

    • 반대로 food 테이블을 기준으로 id가 1인 고객이 주문한 음식 정보 조회
    SELECT u.name as username, f.name as foodname, o.order_date as orderdate FROM food f
        INNER JOIN orders o on f.id = o.food_id
        INNER JOIN users u on o.user_id = u.id WHERE u.id = 1;

     

    • DB에서는 어떤 테이블을 기준으로 하든 원하는 정보를 JOIN을 사용하여 조회할 수 있습니다.
      DB 테이블 간의 관계에서는 방향의 개념이 존재하지 않는다.

    - Entity 간의 연관 관계 (양방향 연관관계)

    그렇다면 JPA Entity에서는 이러한 테이블 간의 연관 관계를 어떻게 표현하고 있을까요?

    Food : User = N : 1 의 관계를 Entity (Java class)로 표현하면 다음과 같습니다.

    • Food Entity
    @Entity
    @Getter
    @NoArgsConstructor
    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;
    
        public Food(String name, double price) {
            this.name = name;
            this.price = price;
        }
    }

     

    • User Entity
    @Entity
    @Getter
    @Table(name = "users")
    @NoArgsConstructor
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
    
        @OneToMany(mappedBy = "user")
        private List<Food> foodList = new ArrayList<>();
        
        public User(String name) {
            this.name = name;
        }
    }

     

    • 한명의 고객이 여러번의 주문을 할 수 있는 상황을 가정했습니다.
      이를 Entity에서 표현하기 위해 List<Food> foodList = new ArrayList<>() 로 표현할 수 있습니다.

    • DB 테이블에서는 User나 Food 테이블 어느 것을 기준으로 음식의 정보를 조회하더라도 JOIN을 사용하여 바로 조회가 가능하지만 User Entity 입장에서는 Food Entity의 정보를 가지고 있지 않으면 음식의 정보를 조회할 수 없습니다.
      이를 해소하기 위해 DB 테이블에는 컬럼으로 존재하지 않지만, Entity 상태에서 다른 Entity를 참조하기 위해 이러한 방법을 사용합니다.

    • 현재 User Entity와 Food Entity는 서로를 참조하고 있으며, 양방향 관계를 갖습니다.

    - Entity 간의 연관 관계 (단방향 연관관계)

    단방향 연관관계는 다음과 같이 표현할 수 있습니다.

    • Food Entity
    @Entity
    @Getter
    @NoArgsConstructor
    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;
    
        public Food(String name, double price) {
            this.name = name;
            this.price = price;
        }
    }

     

    • User Entity
    @Entity
    @Getter
    @Table(name = "users")
    @NoArgsConstructor
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        
        public User(String name) {
            this.name = name;
        }
    }

     

    • Food Entity에서만 User Entity를 참조할 수 있으며, 이러한 관계를 단방향 관계라고 합니다.
    • User Entity에서는 Food Entity의 정보가 없기 때문에 음식에 대한 정보를 조회할 수 없습니다.

     

    정리하자면
    DB 테이블에서는 연관관계를 FK(외래키)로 맺을 수 있고, Entity에서는 상대 Entity를 참조(객체주소)하여 연관관계를 맺을 수 있습니다.
    따라서 Entity에서는 DB 테이블에는 없는 방향의 개념을 갖습니다.

     

    댓글