📌단방향 연관관계

한쪽 클래스만 다른 쪽 클래스의 참조 정보를 가지고 있는 관계를 단방향 연관 관계라고 한다.

 

 

 

📌양방향 연관 관계

양쪽 클래스가 서로의 참조 정보를 가지고 있는 관계를 양방향 연관 관계라고 한다.

 

 

 

📌일대다 단방향 연관 관계(일에서 다의 정보를 가지고 있음)

일대다- 일(1)에 해당하는 클래스가 다(N)에 해당하는 객체를 참조할 수 있는 관계

한명의 회원이 여러 건의 주문을 할 수 있으므로 Member와 Order는 일대다 관계이며, Member만 List 객체를 참조할 수 있으므로 단방향 관계이다.

 

 

일대다 단방향 매핑은 잘 사용하지 않는다.

 

위의 일대다 단반향 연관 관계에서 Order 클래스가 ‘테이블 관계에서 외래키에 해당하는 MEMBER 클래스의 참조값’을 가지고 있지 않아 일반적인 테이블 간의 관계를 정상적으로 표현하지 못하기 때문이다.

테이블 간의 관계에서는 일대다 중에서 ‘다’에 해당하는 테이블에서 ‘일’에 해당하는 테이블의 기본키를 외래키로 가진다.

일대다 단방향 매핑 하나만 사용하기보단 다대일 단방향 매핑을 먼저 한 후에 필요한 경우, 일대다 단방향 매핑을 추가해서 양방향 연관 관계를 만드는 것이 일반적이다.

 

 

📌다대일 연관 관계(다에서 일의 정보를 가지고 있음)

다(N)에 해당하는 클래스가 일(1)에 해당하는 객체를 참조할 수 있는 관계

 

 

다대일 단방향 매핑은 에서 ORDERS 테이블이 MEMBER 테이블의 member_id를 외래키로 가지듯이 Order 클래스가 Member 객체를 외래키처럼 가지고 있음.

테이블 간의 관계와 가장 비슷하기에 JPA의 엔티티 연관 관계 중에서 가장 기본으로 사용

 

 

 

✔ 코드로 보는 다대일 연관 관계 매핑 방법

 

  • 다(N)에 해당하는 Order 클래스
@NoArgsConstructor
@Getter
@Setter
@Entity(name = "ORDERS")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long orderId;

    @Enumerated(EnumType.STRING)
    private OrderStatus orderStatus = OrderStatus.ORDER_REQUEST;

    @Column(nullable = false)
    private LocalDateTime createdAt = LocalDateTime.now();

    @Column(nullable = false, name = "LAST_MODIFIED_AT")
    private LocalDateTime modifiedAt = LocalDateTime.now();

		
    @ManyToOne   // (1)@ManyToOne 애너테이션으로 다대일의 관계를 명시
    @JoinColumn(name = "MEMBER_ID")  // (2)@JoinColumn 애너테이션으로 ORDERS 테이블에서 외래키에 해당하는 컬럼명을 적어줍니다.
    private Member member;

    public void addMember(Member member) { //멤버 객체를 추가할 수 있는 에드메서드 추가
        this.member = member;
    }
    
    //뒷부분 코드 생략

다대일 단방향 연관 관계이기 때문에 코드 3-129의 (1), (2)와 같이 다(N)쪽에서만 설정을 해주면 됨

 

 

이제 실제 테이블에 정보를 저장해보자!

 

✔ 다대일 매핑을 이용한 회원과 주문 정보 저장

private void mappingManyToOneDirection(){
        tx.begin();
        Member member = new Member("hgd@gmail.com","Hong Gil Dong","010-1111-1111");

        em.persist(member); //영속성에 객체 정보 저장

        Order order = new Order(); //Order객체 생성
        order.addMember(member); //order에 addMember메소드 사용하여 member객체 정보 저장(member_ID 와 같은 외래키 역할)
        em.persist(order); //order 주문정보 영속성에 저장

        tx.commit(); //영속성에 있는 객체들 dataTable에 저장(쿼리문 실행)

        Order findOrder = em.find(Order.class, 1L); //order class에 있는 1L정보 가져옴


//주문에 해당하는 회원 정보 가져옴(findOrder.getMember().getMemberId()처럼 객체를 통해 다른 객체의 정보를 가져오는 것 => 객체 그래프 탐색)
        System.out.println("findOrder: " + findOrder.getMember().getMemberId()+  ", " + findOrder.getMember().getEmail());


    }

처럼 다대일 관계에서는 일(1)에 해당하는 객체의 정보를 얻을 수 있다.

 

 

✔ 다대일 매핑에 일대다 매핑 추가

위 방식처럼 다대일 매핑으로 매핑했을 경우

카페 주인 입장에서는 이 주문을 누가 했는지 주문한 회원의 회원 정보를 알아야 할 경우에는 주문한 사람의 정보를 조회할 수 있으나, member 객체를 통해 내가 주문한 주문 정보인 order 객체들을 조회할 수 없기 때문에 회원 입장에서는 자신이 주문한 주문의 목록을 확인할 수 없다.

 

따라서 이 경우, 다대일 매핑이 되어 있는 상태에서 일대다 매핑을 추가해 양방향 관계를 만들어주어야 한다.

 

 

  • 일대다에서 일(1)에 해당하는 Member 클래스
@NoArgsConstructor
@Getter
@Setter
@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long memberId;

    @Column(nullable = false, updatable = false, unique = true)
    private String email;

    @Column(length = 100, nullable = false)
    private String name;

    @Column(length = 13, nullable = false, unique = true)
    private String phone;

    @Column(nullable = false)
    private LocalDateTime createdAt = LocalDateTime.now();

    @Column(nullable = false, name = "LAST_MODIFIED_AT")
    private LocalDateTime modifiedAt = LocalDateTime.now();

		// (1)다대일 매핑에 일대다 매핑을 추가해서 양방향 관계를 만들어주었습니다.
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>(); //Order객체 정보를 리스트로 저장

    public Member(String email) {
        this.email = email;
    }

    public Member(String email, String name, String phone) {
        this.email = email;
        this.name = name;
        this.phone = phone;
    }

    public void addOrder(Order order) {
        orders.add(order);
    }
}

 

 

🔎🔎🔎🔎🔎@OneToMany(mappedBy = "member")🔎🔎🔎🔎🔎

@OneToMany 뒤에는 애트리뷰트 값으로 mappedBy를 가질 수 있는데 

 

이떄 mappedBy 뒤에는 두 객체 중 외래키 역할을 하는 객체의 참조 이름을 적는다.

외래키의 역할을 하는 필드는 다(N)에 해당하는 클라스 안에 있다.

 

헷갈리지 않게 조심!!

 

일대다 단방향 매핑의 경우에는 mappedBy 애트리뷰트의 값이 필요하지 않다.

mappedBy 는 참조할 대상이 있어야 하는데 일대다 단방향 매핑의 경우 참조할 대상이 없기 때문이다.

 

 

 

 

 

✔ 다대일 매핑에 일대다 매핑을 추가하여 주문 정보 조회

private void mappingManyToOneBiDirection() {
    tx.begin();
    Member member =new Member("hgd@gmail.com", "Hong Gil Dong",  "010-1111-1111");
    Order order = new Order();

    member.addOrder(order); //Member에 order정보 추가
    order.addMember(member);//order에 member정보 추가member가 order의 외래키 역할을 하기 때문에 order 객체 저장 시, 반드시 필요

    em.persist(member);   // 멤버객체 영속성에 저장
    em.persist(order);    // 오더객체 영속성에 저장

    tx.commit(); //쓰기지연에 있는 정보 데이터베이스에 모두 추가

//방금 저장한 회원 정보를 1차 캐시에서 조회
    Member findMember = em.find(Member.class, 1L);
    
	//객체 그래프 탐색 과정
    //이제 회원정보 클래스를 통해서도 주문 정보를 가져올 수 있음(Array리스트에서 객체를 찾아와야 하므로 스트림 사용)
    findMember.getOrders().stream() //주문 객체리스트를 스트림으로 바꿔줌
            .forEach(findOrder -> {
                System.out.println("findOrder:"+findOrder.getOrderId() + "," + findOrder.getOrderStatus());
            });

}
}

 

 

 

📌다대다 연관 관계

하나의 주문에 여러개의 커피가 속할 수 있고, 하나의 커피는 여러 주문에 속할 수 있으니 주문(Order)과 커피(Coffee)의 관계는 다대다 관계

 

테이블 설계 시, 다대다의 관계는 중간에 테이블을 하나 추가해서 두 개의 일대다 관계를 만들어준다.

 

중간 테이블인 ORDER_COFFEE 테이블은 ORDERS 테이블의 외래키와 COFFEE 테이블의 외래키를 가지고 있다.

 

여기서는  먼저 두 개의 다대일 매핑이 필요 

 

그리고 나서 다대일 매핑을 통해 원하는 객체를 조회할 수 없다면 , 일대다 양방향 매핑을 추가한다.

 

 

 

📌일대일 연관관계

일대일 연관 관계 매핑은 다대일 단방향 연관 관계 매핑과 매핑 방법은 동일

@ManyToOne 애너테이션 대신 @OneToOne 애너테이션을 사용한다

 

일대일 단방향 매핑에 양방향 매핑을 추가하는 방법도 다대일에 일대다 매핑을 추가하는 방식과 동일

 

일대일에서는 보통 서브테이블이 주테이블의 외래키를 가진다.

 

//서브테이블 내부
@OneToOne
@JoinColumn(name"MEEMER_ID(외래키명)")
//주 테이블 내부
@OneToOne(mappedBy="member"(외래키 역할을 하는 객체의 참조명))
복사했습니다!