본문 바로가기
JPA

[JPA] 일대일 연관관계 (단방향)

by 2nyong 2023. 4. 28.

목차


    테이블 설계

    일대일 연관관계를 고객(Member)고객이 주문한 음식(Food)을 예시로 설명하겠습니다.

    • 고객(Member)은 하나의 음식(Food)을 주문할 수 있다.
    • 고객(Member) : 음식(Food) = 1 : 1

     

    단방향 연관관계를 위한 추가 조건은 다음과 같습니다.

    • 외래 키의 주인은 Food Entity 이다.
    일대일 관계에서의 외래 키
    Entity에서 외래 키의 주인은 일반적으로 다(N)의 관계인 Entity이지만, 일대일 관계에서는 아무나 외래 키의 주인이 될 수 있으므로 직접 지정해줘야 합니다.
    • Food Entity는 Food.member 필드를 통해 음식을 주문한 고객(Member Entity)에 접근할 수 있다.
    • Member Entity는 Food Entity에 접근할 수 없다.


    Entity 관계 매핑

    - Food Entity

    @Entity
    public class Food {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private double price;
        
        @OneToOne
        @JoinColumn(name = "member_id")
        private Member member;
        
        // constructor, getter, setter, ...
    }

     

    - Member Entity

    @Entity
    public class Member {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
            
        // constructor, getter, setter, ...
    }

     

    • 일대일 단방향 매핑에서는 지정된 외래 키 주인 Entity(Food Entity)쪽에서 반대 Entity(Member Entity)를 참조 필드로 갖습니다.
    • 참조 필드 위에 @OneToOne 애노테이션과 @JoinColumn(name = "{foreign key name}") 애노테이션을 추가로 작성합니다.
    • 위의 Entity 관계를 적용하여 테이블을 생성하였을 때, 실행되는 SQL은  아래와 같습니다.
    create table food (
        id bigint not null auto_increment,
        name varchar(255),
        price float(53) not null,
        member_id bigint,
        primary key (id)
    );
    
    create table member (
        id bigint not null auto_increment,
        name varchar(255),
        primary key (id)
    );
    
    alter table food 
        add constraint FKnyfi1wxbgo0pqliou7xkfe4lw 
        foreign key (member_id) 
        references member (id)

    Entity 관계 사용법

    - 저장

    @Transactional
    @SpringBootTest
    public class OneToOneTest {
    
        @Autowired FoodRepository foodRepository;
        @Autowired UserRepository userRepository;
    
        @Test
        @Rollback(value = false)
        @DisplayName("1대1 단방향 저장 테스트")
        void OneWaySaveTest() {
            // 고객(Member)
            Member member = new Member("2nyong");
            userRepository.save(Member);
            
            // 음식(Food)
            Food food = new Food("후라이드 치킨", 15000);
            foodRepository.save(food);
            food.setMember(member); // 외래 키 입력
        }
    }

     

    • 위 코드 실행 시, 적용되는 SQL은 다음과 같습니다.
    • JPA의 변경감지와 Hibernate의 업데이트 기본 전략에 의해 UPDATE 문이 실행됩니다.
    INSERT INTO MEMBER (NAME) VALUES ('Inyong');
    INSERT INTO FOOD (MEMBER_ID, NAME, PRICE) VALUES (NULL, "후라이드 치킨", 15000);
    UPDATE FOOD SET (MEMBER_ID=1, NAME="후라이드 치킨", PRICE=15000) WHERE FOOD_ID=1;

     

    - 조회

    @Transactional
    @SpringBootTest
    public class OneToOneTest {
    
        @Autowired FoodRepository foodRepository;
        @Autowired MemberRepository memberRepository;
    
        @Test
        @DisplayName("1대1 단방향 조회 : Food 기준 Member 정보 조회")
        void OneWayViewTest() {
            // 음식 정보 조회
            Food food = foodRepository.findById(1L).orElseThrow(NullPointerException::new);
            System.out.println("food.getName() = " + food.getName());
    
            // 음식을 주문한 고객 정보 조회
            System.out.println("food.getMember().getName() = " + food.getMember().getName());
        }
    }
    
    // 출력 결과
    // food.getName() = 후라이드 치킨
    // food.getMember().getName() = Inyong

     

    • 위 코드 실행 시, 적용되는 SQL은 다음과 같습니다.
    SELECT f.ID, m.ID, m.NAME, f.NAME, f.PRICE FROM FOOD f
        LEFT JOIN MEMBER m ON m.ID = f.MEMBER_ID
    WHERE f.ID = 1

     

    댓글