JPA는 연관관계에 있는 상대 테이블의 PK를 멤버변수로 갖지 않고, 엔티티 객체 자체를 통째로 참조
예시
// JDBC(Mybatis)
private Integer categoryNo;
// JPA
private Category category
관계의 방향
다중성
관계에 있는 두 엔티티는 다음 중 하나의 관계를 갖음
연관 관계의 주인
연관 관계를 갖는 두 테이블에 대해서 외래키를 갖는 테이블이 연관관계의 주인이됨
주인만 왜래키를 관리(등록, 수정, 삭제)할 수 있고, 주인이 아닌 엔티티는 읽기만 가능
@Entity
@Table(name="category")
public class Category {
@Id
@Column(name="no")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer no;
@Column( name="name", nullable=false, length=100 )
private String name;
// getter , setter 생략
}
@Entity
@Table( name="book")
public class Book {
@Id
@Column(name="no")
@GeneratedValue( strategy = GenerationType.IDENTITY )
private Integer no;
@Column(name="title", nullable=false, length=200)
private String title;
@ManyToOne
@JoinColumn(name ="category_no")
private Category category;
// getter , setter 생략
}
Book 엔티티에서만 Category를 참조중이므로 여기만 ManyToOne 사용 여러 책들이 하나의 카테고리에 속하므로 N:1의 관계 JoinColumn은 FK 매핑시 사용, name 속성에는 매핑할 FK 이름 넣기 Category 엔티티의 no를 FK로 가지므로 name속성을 category_no로 작성 테이블 연관관계 @Entity
@Table(name="category")
public class Category {
@Id
@Column(name="no")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer no;
@Column( name="name", nullable=false, length=100 )
private String name;
// Category는 Book을 List로 가짐
// OneToMany에 mappedBy속성을 추가하여 JPA에게 연관관계의 주인이 아님을 알려줌
// -> 카테고리에 여러개의 책이 속하므로 OneToMany를 달아주고
// books 필드는 category에 의해 매핑되므로, mappedBy="category" 작성
// 참고로 "category"는 Book 엔티티에서 Category를 참조할 때 작성한 필드명
@OneToMany(mappedBy="category")
private List<Book> books = new ArrayList<Book>();
// getter , setter 생략
}
Category는 Book을 List로 가짐 OneToMany에 mappedBy속성을 추가하여 JPA에게 연관관계의 주인이 아님을 알려줌 -> 카테고리에 여러개의 책이 속하므로 OneToMany를 달아주고 books 필드는 category에 의해 매핑되므로, mappedBy="category" 작성참고로 "category"는 Book 엔티티에서 Category를 참조할 때 작성한 필드명
```java
@ManyToOne
@JoinColumn(name ="category_no")
private Category category;
```
테이블 연관 관계는 동일
한 유저가 여러개의 블로그를 가질 수 있도록 확장성을 고려하여 블로그에서 유저의 PK를 FK로 갖기
유저를 조회 했을 때 블로그까지 조회할 수 있도록 유저에서 블로그의 PK를 FK로 갖기
→ 아래 예제는 2번으로 선택(FK를 가지고 있는 테이블인 유저가 주 테이블)
[단방향]
@Entity
@Table(name="user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="no")
private Integer no;
@Column(name="id")
private String id;
@OneToOne
@JoinColumn(name="blog_no")
private Blog blog;
}
@Entity
@Table(name="blog")
public class Blog {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="no")
private Integer no;
@Column(name="name")
private String name;
}
User 엔티티에서만 Blog 엔티티 참조 → 1:1 단방향
JoinColumn으로 User에서 Blog의 id를 FK로 매핑
[양방향]
@Entity
@Table(name="blog")
public class Blog {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="no")
private Integer no;
@Column(name="name")
private String name;
@OneToOne(mappedBy="blog")
private User user;
}
Blog 엔티티에서도 User 참조
주인은 User 엔티티이므로 Blog 엔티티의 User필드에 mappedBy 속성으로 “blog” 지정
테이블 연관 관계
@Entity
@Table(name="user")
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="no")
private Integer no;
@Column(name="id")
private String id;
@ManyToMany
@JoinTable(name="user_product",
joinColumns = @JoinColumn(name = "user_no"),
inverseJoinColumns = @JoinColumn(name = "product_no"))
private List<Product> product = new ArrayList<Product>();
}
@Entity
@Table(name="product")
public class Product {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Integer id;
@Column(name="name")
private String name;
}
@JoinTable 어노테이션은 M:N 관계에서 생성할 테이블 명을 정의 name 속성으로 새로 생성할 테이블의 이름을 정의 joinColumns 속성으로 join을 수행할 자신의 칼럼 이름을 작성 inverseJoinColumns 속성으로 join을 수행할 다른 칼럼 이름을 작성 → FK로 product_no 와 user_no를 가진 user_product 라는 중간 테이블이 생성됨 [양방향]@Entity
@Table(name="product")
public class Product {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Integer id;
@Column(name="name")
private String name;
@ManyToMany(mappedBy="products")
private List<User> users = new ArrayList<User>();
}
중간테이블을 따로 정의하기 만약 user와 product 사이에 cart라는테이블 만든다고 하면@Entity
@Table(name="cart")
@IdClass(CartId.class)
public class Cart {
@Id
@ManyToOne
@JoinColumn(name="user_no", nullable=false)
private User user;
@Id
@ManyToOne
@JoinColumn(name="product_id", nullable=false)
private Product item;
@Column(name="count", nullable=false)
private Integer count;
}
public class CartId implements Serializable{
private Integer user;
private Integer product;
// getter setter 생략
}
이런식으로 Cart 엔티티를 정의하고, User와 Product 엔티티의 PK를 복합키로 정의하기 위해 CartId 라는 클래스를 따로 정의하고 그리고 User와 Product 엔티티의 관계 엔티티인 Cart 엔티티를 정의할 때 @IdClass 어노테이션을 작성