Entity 연관 관계

yesrin·2023년 6월 22일

JPA

목록 보기
1/7

DB 테이블에서는 테이블 사이의 연관관계를 FK(외래 키)로 맺을 수 있고 방향 상관없이 조회가 가능합니다.

Entity에서는 상대 Entity를 참조하여 Entity 사이의 연관관계를 맺을 수 있습니다.
하지만 상대 Entity를 참조하지 않고 있다면 상대 Entity를 조회할 수 있는 방법이 없습니다.

따라서 Entity에서는 DB 테이블에는 없는 방향의 개념이 존재합니다.
한쪽에서만 참조하고 있다면 단방향, 서로 참조하고 있다면 양방향

1 대 1 관계

@OneToOne
@OneToOne 애너테이션은 1 대 1 관계를 맺어주는 역할을 합니다.

단방향 관계

Entity에서 외래 키의 주인은 일반적으로 N(다)의 관계인 Entity 이지만 1 대 1 관계에서는 외래 키의 주인을 직접 지정해야합니다.

외래 키 주인만이 외래 키** 를 등록, 수정, 삭제할 수 있으며,주인이 아닌 쪽은 오직 외래 키를 읽기만 가능합니다.

@JoinColumn()은 외래 키의 주인이 활용하는 애너테이션입니다.
컬럼명, null 여부, unique 여부 등을 지정할 수 있습니다.

양방향 관계

양방향 관계에서 외래 키의 주인을 지정해 줄 때 mappedBy 옵션을 사용합니다.

mappedBy의 속성값은 외래 키의 주인인 상대 Entity의 필드명을 의미합니다.

N 대 1 관계

@ManyToOne
@ManyToOne 애너테이션은 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
@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<>();
}

1 대 N 관계

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

단방향 관계

외래 키를 관리하는 주인은 음식 Entity이지만 실제 외래 키는 고객 Entity가 가지고 있습니다.

음식

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @OneToMany
    @JoinColumn(name = "food_id") // users 테이블에 food_id 컬럼
    private List<User> userList = new ArrayList<>();
}

고객

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @OneToMany
    @JoinColumn(name = "food_id") // users 테이블에 food_id 컬럼
    private List<User> userList = new ArrayList<>();
}

양방향 관계

1 대 N 관계에서는 일반적으로 양방향 관계가 존재하지 않습니다.
1 대 N 관계에서 양방향 관계를 맺으려면 음식 Entity를 외래 키의 주인으로 정해주기 위해 고객 Entity에서 mappedBy 옵션을 사용해야 하지만 @ManyToOne 애너테이션은 mappedBy 속성을 제공하지 않습니다.

```java
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

		@ManyToOne
		@JoinColumn(name = "food_id", insertable = false, updatable = false)
		private Food food;
}
```

N 관계의 Entity인 고객 Entity에서 @JoinColum의 insertable 과 updatable 옵션을 false로 설정하여 양쪽으로 JOIN 설정을 하면 양방향처럼 설정할 수는 있습니다.

N 대 M 관계

@ManyToMany
@ManyToMany 애너테이션은 N 대 M 관계를 맺어주는 역할을 합니다.

단방향 관계
생성되는 중간 테이블을 컨트롤하기 어렵기 때문에 추후에 중간 테이블의 변경이 발생할 경우 문제가 발생할 가능성이 있습니다.

N : M 관계를 풀어내기 위해 중간 테이블(orders)을 생성하여 사용합니다.

양방향관계

반대 방향인 고객 Entity에 @ManyToMany 로 음식 Entity를 연결하고 mappedBy 옵션을 설정하여 외래 키의 주인을 설정하면 양방향 관계 맺음이 가능합니다.

지연 로딩

  • JPA는 연관관계가 설정된 Entity의 정보를 바로 가져올지, 필요할 때 가져올지 정할 수 있습니다.
    • 즉, 가져오는 방법을 정하게되는데 JPA에서는 Fetch Type이라 부릅니다.
    • Fetch Type의 종류에는 2가지가 있는데 하나는 LAZY, 다른 하나는 EAGER 입니다.
    • LAZY지연 로딩으로 필요한 시점에 정보를 가져옵니다.
    • EAGER즉시 로딩으로 이름의 뜻처럼 조회할 때 연관된 모든 Entity의 정보를 즉시 가져옵니다.
  • 기본적으로 @OneToMany 애너테이션은 Fetch Type의 default 값이 LAZY로 지정되어있고 반대로 @ManyToOne 애너테이션은 EAGER로 되어있습니다.
    다른 연관관계 애너테이션들도 default 값이 있는데 이를 구분하는 방법이 있습니다.
    • 애너테이션 이름에서 뒤쪽에 Many가 붙어있으면 설정된 해당 필드가 Java 컬렉션 타입일 것입니다.
      - 즉, 해당 Entity의 정보가 여러 개 들어있을 수 있다는 것을 의미합니다.
      - 따라서 효율적으로 정보를 조회하기 위해 지연 로딩이 default로 설정되어있습니다.
      • 반대로 이름 뒤쪽이 One일 경우 해당 Entity 정보가 한 개만 들어오기 때문에 즉시 정보를 가져와도 무리가 없어 즉시 로딩이 default로 설정되어있습니다.

읽는건 트렌젝션이 필수가 아니지만,
지연 로딩이 된 엔티티를 조회하고 싶다면 트렌젝션 필수.

profile
안녕하세요! 틀린 정보는 댓글 달아 주세요.

0개의 댓글