다대일

1.다대일 단방향 [N:1]

@Entity
public class Member {
	
	@ManyToOne
	@JoinColumn(name = TEAM_ID)
	private Team team;
	
}
@Entity
public class Team {
	@Id @GeneratedValue
	@Column(name = TEAM_ID)
	private Long id;

}

Member.team으로 팀 엔티티를 참조, 반대로 참조하는 필드 없음


2.다대일 양방향[N:1, 1:N]

@Entity
public class Member {
	
	@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 {
	
	@OneToMany(mappedBy = team)
	private List<Member> members = new ArrayList<Member>();
	
	public void addMember(Member member) {
		this.member.add(member);
		if (member.getTeam() != this) {	//무한루프에 빠지지 않도록 체크
			member.setTeam(this);
        }
    }

}
  • 양방향은 외래 키가 있는 쪽이 연관관계의 주인이다. (Member.team이 주인)
  • 양방향 연관관계는 항상 서로를 참조해야한다. (편의 메소드 setTeam(), addMember())


일대다

1.일대다 단방향 [1:N]

상황 – 하나의 팀은 여러 회원을 참조할 수 있고 반대로 회원은 팀을 참조하지 않으면 된다.

@Entity
public class Team {
	
	@OneToMany(mappedBy = team)
	@JoinColumn(name = TEAM_ID) // MEMBER 테이블의 TEAM_ID (FK)
	private List<Member> members = new ArrayList<Member>();
	
}
@Entity
public class Member {
	@Id @GeneratedValue
	@Column(name = MEMBER_ID)
	private Long id;
	
}
  • 일대다 단방향 매핑을 사용하면 엔티티를 매핑한 테이블이 아닌 다른 테이블의 외래 키를 관리해야 하므로 다대일 양방향 매핑을 사용하자


2.일대다 양방향 [1:N, N:1]

@Entity
public class Team {
	
	@OneToMany(mappedBy = team)
	@JoinColumn(name = TEAM_ID)
	private List<Member> members = new ArrayList<Member>();
	
}
@Entity
public class Member {
	
	@ManyToOne
	@JoinColumn(name = TEAM_ID, insertable = false, updatable = false)
	private Team team;
	
}
  • 일대다 단방향 매핑 반대편에 다대일 단방향 매핑을 읽기 전용으로 추가해서 일대다 양방향처럼 보이도록 하는 방법


일대일[1:1]

주 테이블 외래 키 – 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.

대상 테이블 외래 키 – 테이블 관계를 일대일에서 일대다로 변경할 때 테이블 구조를 유지할 수 있다.

1.주 테이블 외래 키

1-1.단방향

@Entity
public class Member {
	@Id @GemeratedValue
	@Column(name = MEMBER_ID)
	private Long id;
	
	@OneToOne
	@JoinColumn(name = LOCKER_ID)
	private Locker locker;
	
}

@Entity
public class Locker {
	@Id @GeneratedValue
	@Column(name = LOCKER_ID)
	private Long id;
	
}

1-2.양방향

@Entity
public class Member {
	@Id @GemeratedValue
	@Column(name = MEMBER_ID)
	private Long id;
	
	@OneToOne
	@JoinColumn(name = LOCKER_ID)
	private Locker locker;
	
}

@Entity
public class Locker {
	@Id @GeneratedValue
	@Column(name = LOCKER_ID)
	private Long id;
	
	@OneToOne(mappedBy = locker)
	private Member member;
}

2.대상 테이블에 외래키

2-1.일대일 단방향 허용 X

2-2.일대일 양방향

@Entity
public class Member {
	@Id @GemeratedValue
	@Column(name = MEMBER_ID)
	private Long id;
	
	@OneToOne(mappedBy = member)
	private Locker locker;
	
}

@Entity
public class Locker {
	@Id @GeneratedValue
	@Column(name = LOCKER_ID)
	private Long id;
	
	@OneToOne
	@JoinColumn(name = MEMBER_ID)
	private Member member;
}


다대다 [N:N]

1.단방향

@Entity
public class Member {
    @Id @Column(name = MEMBER_ID)
    private String id;
    
    @ManyToMany
    @JoinTable(name = MEMBER_PRODUCT, joinColumns = @JoinColumn(name=MEMBER_ID), inverseJoinColumns = @JoinColumn(name = PRODUCT_ID))
    private List<Product> products = new ArryaList<Product>();
}

2.양방향

@Entity
public class Product {
	
	@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;
}

@Enitty
@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와 연결

}

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() {}p
}

특징

  • 복합 키는 별도의 식별자 클래스로 만들어야 한다.
  • Serializable을 구현해야 한다.
  • equals와 hashCode 메소드를 구현해야 한다.
  • 기본 생성자가 있어야 한다.
  • 식별자 클래스는 public이어야 한다.
  • @IdClass를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있다.

다대다: 새로운 기본 키 사용

@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;

}


출처 : 자바 ORM 표준 JPA 프로그래밍 김영한 지음