본문 바로가기
책벌레와 벌레 그 사이 어딘가/개념쌓기

[개념쌓기] 연관관계 매핑

by veganwithbacon 2022. 8. 10.
반응형

엔티티( Entity )들은 대부분 서로 관계를 맺고 있다.

예를들어 Category 엔티티와 Book 엔티티가 있을 때, Category에는 많은 Book을 갖는 관계를 갖고 있습니다.

이렇게 엔티티들이 서로 어떤 연관관계를 맺는지 파악하는 것은 매우 매우 중요하다

 

 

  연관관계 매핑?

객체의 참조와 테이블의 외래키를 매핑하는 것

Jpa에서는 상대 테이블의 PK를 멤버변수로 갖지 않고,엔티티 객체 자체를 통으로 참조한다

 

 

  단방향?양방향?

단방향 관계 : 두 엔티티가 관계를 맺을 때, 한 쪽의 엔티티만 참조하고 있는 것

양방향 관계 : 두 엔티티가 관계를 맺을 때, 양 쪽이 서로 참조하고 있는 것

 

데이터 모델링에서는 관계를 맺기만 하면 자동으로 양방향 관계가 되어 서로 참조하나, 

객체지향 모델링에서는 구현하고자 하는 서비스가 단방향인지,양방향인지 적절하게 선택해야한다.

예를 들어 Intellij에서 자바를 통해 모델링을 하면 선택에 따라 서비스가 단방향인지 양방향인지 바뀌게 된다.

 

  어느 정도의 비즈니스에서는 단방향 관계만으로도 해결이 가능하기 때문에 양방향 관계를 꼭 해야 하는 것은 아니다

 

 

  다중성?

관계에 있는 두 엔티티는 다음 중 하나의 관계를 갖는다

Many To One   - 다대일( N : 1 )

One To Many   - 일대다( 1 : N )

One To One    - 일대일( 1 : 1 )

Many To Many - 다대다( N : N ) 

 

예를들어 카테고리는 많은 서적을 갖고 있으므로 카테고리 입장에서는 서적과 일대다 관계이며,

서적의 입장에서는 하나의 카테고리에 속하므로 다대일 관계이다.

즉, 어떤 엔티티를 중심으로 상대 엔티티를 바라 보느냐에 따라 다중성이 다르다

 

  연관 관계의 주인(Owner)

연관 관계에서 주인을 결정한다

주인을 찾는 방법은 연관 관계를 갖는 두 테이블에 대해서 외래키를 갖는 테이블이 연관 관계의 주인이 된다

연관관계의 주인만이 외래 키를 관리(등록, 수정, 삭제) 할 수 있고, 반면 주인이 아닌 엔티티는 읽기만 할 수 있습니다.

 

 

  1. @ManyToOne - 단방향

@Entity
@Table(name="classroom")
public class Classroom{
	@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="student")
public class Student {
	@Id
	@Column(name="no")
	@GeneratedValue( strategy = GenerationType.IDENTITY )
	private Integer no;
	
	@Column(name="title", nullable=false, length=200)
	private String title;
	
	@ManyToOne
	@JoinColumn(name ="classroom_no")
	private Classroom classroom;
	
	// getter , setter 생략
	
}

단방향은 한 쪽의 엔티티가 상대 엔티티를 참조하고 있는 상태이다.

그래서 Student 엔티티에만 @ManyToOne 어노테이션을 추가하게 되었다

 

@ManyToOne

@ManyToOne 어노테이션은 이름 그대로 다대일( N : 1 ) 관계 매핑 정보이다

교실 입장에서는 학생과 다대일 관계이므로 @ManyToOne이 된다.

연관관계를 매핑할 때 이렇게 다중성을 나타내는 어노테이션(@ManyToMany, @OneToOne 등…)은 필수로 사용해야 하며, 엔티티 자신을 기준으로 다중성을 생각해야한다.

 

@JoinColumn(name="classroom_no")

@JoinColumn 어노테이션은 외래키를 매핑할 때 사용한다

name 속성에는 매핑할 외래키 이름을 지정한다

 

예시에서는 외래키가 있는 Student는 classroom에서 정보들을 받아올 수 있는데

반대로 Classroom에서 Student의 정보를 받으려면 JPA에서는 양방향 관계를 맺음으로 해결할 수 있다.

 

 

   2.@OneToMany 를 통해 양방향 맺기

@Entity
@Table(name="classroom")
public class Classroom {
	@Id
	@Column(name="no")
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer no;
	
	@Column( name="name", nullable=false, length=100 )
	private String name;

	@OneToMany(mappedBy="category")
	private List<Student> students = new ArrayList<Student>();
	
	// getter , setter 생략
	
}

 

Classroom은 Student를 List로 가지며, @OneToMany 어노테이션에 mappedBy 속성을 추가했다

 

연관관계 주인 정하기

- 주인은 mappedBy 속성을 사용하지 않는다

- 주인이 아니면 mappedBy 속성을 사용해 속성의 값으로 연관관계의 주인을 정할 수 있다.

 

주인은 mappedBy속성을 사용할 수 없다

 

단방향 관계를 맺은 상태에서 Classroom이 Student쪽으로 단방향 연결을 해줬기 때문에 양방향 관계가 성립되었다

 

양방향 관계든,단방향 관계든 테이블을 정의하는 SQL도 똑같다

외래키는 Student에 있다

 

   3.@OneToOne

   *️⃣ 1:1 관계에서는 둘 중 어느 테이블이나 외래 키를 가질 수 있다

           그러므로,두 엔티티 중 누가 외래키를 가질지 선택해야 한다

   *️⃣ 보통 Access가 많은 엔티티를 주 테이블로 정한다

   *️⃣  @OneToOne 어노테이션을 외래키로 매핑할 필드에 추가한다

   *️⃣  DB에서 주 테이블에 외래키 필드에 유니크 조건을 설정한다

   *️⃣ 양방향 관계인 경우 주인이 아닌 쪽에 mappedBy를 작성하면 된다

 

위의 경우들과 마찬가지로 주테이블만 확인해도 대상 테이블과 연관 관계 유무를 확인할 수 있고

외래키를 객체 참조와 비슷하게 사용할 수도 있다

 

   경우 따지기

 

@ManyToMany 의 경우도 마찬가지다

 

위의 예를 똑같이 한번 더 들게 되면

 

학생 한명이 교실 하나에 있을 수 있다          ( O ) 

학생 여러명이 교실 하나에 있을 수 있다      ( O )

학생 한명이 교실 여러개에 있을 수 있다       ( X )

학생 여러명이 교실 여러개에 있을 수 있다    (  X )

 

위의 다대다의 경우는 말이 안되는 것이 아니라 일대다의 관계에서 막히기 때문에 경우를 따지지 않은 것이다.

위와 같이  하나씩 경우를 따져보면 관계를 알아낼 수 있고,외래키가 어디에 있어야하는지도 알 수 있게 된다.

반응형

댓글