참고로 다중성은 왼쪽을 연관관계의 주인으로 정함
객체의 양방향 관계에서 연관관계의 주인은 항상 다쪽
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
// Getter, Setter
...
}
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
// Getter, Setter
...
}
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
public void setTeam(Team team) {
this.team = team;
// 무한루프에 빠지지 않도록 체크
if (!team.getMembers().contains(this)) {
team.getMembers.().add(this);
}
}
}
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
public void addMember(Member member) {
this.members.add(member);
if (member.getTeam() != this) { // 무한루프에 빠지지 않도록 체크
member.setTeam(this);
}
}
...
}
일대다 관계는 엔티티를 하나 이상 참조할 수 있으므로 자바 컬렉션인 Collection, List, Set, Map 중에 하나를 사용해야 함
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
// Getter, Setter
...
}
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<Member>();
// Getter, Setter
...
}
@OneToMany, @ManyToOne 둘 중에 연관관계의 주인은 항상 다 쪽인 @ManyToOne을 사용한 곳
따라서 @ManyToOne에는 mappedBy 속성 없음
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID", insertable = false,
updatable = false)
private Team team;
// Getter, Setter
...
}
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMamy
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<Member>();
// Getter, Setter
...
}
프록시를 사용할 때 외래 키를 직접 관리하지 않는 일대일 관계는 지연 로딩으로 설정해도 즉시 로딩됨.
@Entity
public class Member {
@Id @Column(name = "MEMBER_ID")
private String id;
private String username;
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT",
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
private List<Product> products = new ArrayList<Product>();
...
}
@Entity
public class Product {
@Id @Column(name = "PRODUCT_ID")
private String id;
private String name;
...
}
@Entity
public class Member {
@Id @Column(name = "MEMBER_ID")
private String id;
private String username;
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT",
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
private List<Product> products = new ArrayList<Product>();
// 연관관계 편의 메소드
public void addProduct(Product product) {
...
products.add(product);
product.getMembers().add(this);
}
...
}
@Entity
public class Product {
@Id @Column(name = "PRODUCT_ID")
private String id;
@ManyToMany(mappedBy = "products") // 역방향 추가
private List<Member> members;
...
}
@Entity
public class Member {
@Id @Column(name = "MEMBER_ID")
private String id;
// 역방향
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts;
...
}
@Entity
public class Product {
@Id @Column(name = "PRODUCT_ID")
private String id;
private String name;
...
}
@Entity
@IdClass (MemberProductId.class)
public class MemberProduct {
@Id
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member; // MemberProductId.member와 연결
@Id
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product; // MemberProductId.product와 연결
private int orderAmount;
...
}
public class MemberProductId implements Serializable {
private String member; // MemberProduct.member와 연결
private String product; // MemberProduct.product와 연결
// hashCode and equals
@Override
public boolean equals(Object o) {...}
@Override
public int hashCode() {...}
...
}
복합 기본 키
- JPA에서 복합 키를 사용하려면 별도의 식별자 클래스를 만들어야 함
- 엔티티에 @IdClass를 사용해서 식별자 클래스를 지정하면 됨
- 특징
- 복합 키는 별도의 식별자 클래스로 만들어야 함
- Serializable을 구현해야 함
- equals와 hashCode 메소드를 구현해야 함
- 기본 생성자가 있어야 함
- 식별자 클래스는 public이어야 함
- @IdClass를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있음
식별 관계
- 부모 테이블의 기본 키를 받아서 자신의 기본 키 + 외래 키로 사용하는 것
// 조회 코드
public void find() {
// 가본 키 값 생성
MemberProductId memberProductId = new MemberProductId();
memberProductId.setMember("member1");
memberProductId.setProduct("productA");
MemberProduct memberProduct = em.find(MemberProduct.class, memberProductId);
Member member = memberProduct.getMember();
Product product = memberProduct.getProduct();
System.out.println("member = " + member.getUsername());
System.out.println("product = " + product.getName());
System.out.println("orderAmount = " + memberProduct.getOrderAmount());
}
데이터베이스에서 자동으로 생성해주는 대리 키를 Long 값으로 사용
@Entity
public class Order {
@Id @GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
private int orderAmount;
...
}
@Entity
public class Member {
@Id @Column(name = "MEMBER_ID")
private String id;
private String username;
@OneToMany(mappedBy = "member)
private List<Order> orders = new ArrayList<Order>();
...
}
@Entity
public class Product {
@Id @Column(name = "PRODUCT_ID")
private String id;
private String name;
...
}
// 조회 코드
public void find() {
Long orderId = 1L;
Order order = em.find(Order.class, orderId);
Member member = order.getMember();
Product product = order.getProduct();
...
}
- 식별 관계: 받아온 식별자를 기본 키 + 외래 키로 사용
- 비식별 관계: 받아온 식별자는 외래 키로만 사용하고 새로운 식별자 추가