이전에 실습했던 간단한 게시판 만들기 프로젝트에서는 일대다, 다대다 관계를 설정해 본 적이 없었다. 하지만 현재 진행하는 프로젝트 ERD에는 일대다, 다대다 관계가 필수였기에 관련 개념을 알아보았다.
관계의 다중성
단방향인가, 양방향인가
양방향일 경우 두 테이블 중 외래키를 관리할 테이블을 정해야 한다.
회원 한 명이 여러 가게를 소유할 수 있다
가게들(N):회원(1) => 가게(N)가 회원(1)을 참조
가게(N)에서 외래키를 관리한다.
외래키가 존재하는 곳(가게)에서 참조를 걸고 연관관계를 매핑한다.
가게 테이블에서 @JoinColumn(name= "member_id") 어노테이션 설정
가게 테이블에서는 회원을 참조할 수 있지만, 회원 테이블에서는 가게를 참조할 수 없다.
회원 한 명이 여러 가게를 소유할 수 있다.
가게 테이블에서 회원을 참조하고, 회원 테이블에서도 가게 테이블을 참조할 수 있다.
회원 테이블에서 @OneToMany(mappedBy="store")을 설정해준다.
리스트로 가져온다.
회원(1)에서 외래키를 관리한다.
회원(1)에서는 가게(N)들을 조회할 수 있지만 가게(N)에서는 회원(1)을 알 수 없다.
@JoinColumn을 꼭 사용하거나 중간에 테이블을 하나 두는 방식으로 관리해야한다.
연관관계 관리를 위해 추가적으로 UPDATE SQL이 실행된다.
두 테이블 모두에 @JoinColumn이 붙는다...(둘다 연관관계의 주체가 됨)
대신 @JoinColumn(insertable=false, updatable=false)이렇게 설정해서 읽기 전용으로 참고만 해야한다.
제대로 이해한 지 모르겠다.
N:1 단방향 관계에서 어노테이션만 달라진 느낌.
외래키에 유니크 제약조건을 줘야 한다.
연관관계의 주인이 되는 클래스에 @OneToOne, @JoinColumn 을 적용한다.
외래키가 있는 곳이 연관관계의 주체이다.
외래키가 있는 반대 테이블의 필드에 @OneToOne(mappedBy="테이블명")를 지정해준다.
가게 관련 기본 CRUD 기능을 수행하는 코드 작성
domain에는 DB 테이블과 매칭되는 class 파일들이 작성된다.
가게 entity 생성을 위해 Store.java 파일을 생성하고 작성한다.
해서 위에 학습한 개념을 적용해 클래스를 작성해보았다.
case 1
: Store 객체의 입장에서
한 명의 member는 여러 개의 store를 가질 수 있다. member(1) : store(N)
하나의 registrationNumber(사업자등록번호)는 여러 개의 store에 적용될 수 있다. registrationNumber(1) : store(N)
하나의 store는 여러 개의 businessHour를 가질 수 있다. store(1) : businessHour(N)
// Store.java
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Store {
@Id // id 필드를 기본키로 지정한다
@GeneratedValue(strategy = GenerationType.IDENTITY) // 기본키를 자동으로 1씩 증가시킨다
@Column(name = "store_id", updatable = false, nullable = false)
private Long id;
@Column(name = "name", nullable = false)
private name;
// ... 생략
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
// member 하나에 store는 여러 개 존재할 수 있음
@ManyToOne
@JoinColumn(name = "registration_number_id")
private RegistrationNumber registrationNumber;
// registrationNumber 하나에 store는 여러 개 존재할 수 있음
@OneToMany(mappedBy = "store")
private List<BusinessHour> businessHours = new ArrayList<>();
// store 하나에 businessHour는 여러 개 존재할 수 있음
}
// BusinessHour.java
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class BusinessHour {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "business_hour_id", updatable = false, nullable = false)
private Long id;
private day; // 요일
// ... 생략
@ManyToOne
@JoinColumn(name = "store_id")
private Store store;
// store 하나에 영업시간이 여러 개(요일별로) 존재할 수 있음.
}
case 2
: 내가 보유한 기프티콘(socon) 하나는 하나의 게시글(sogon)과 연결될 수 있다.
게시글(sogon)이 외래키를 갖고 기프티콘 엔터티(socon)를 참조한다.
이 경우 기프티콘 엔터티(socon)에서는 외래 키를 저장하지 않는다.
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class Sogon {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "sogon_id", nullable = false)
private Long id;
// ... 생략
@OneToOne
private MySocon mySocon;
}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class MySocon {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "socon_id", updatable = false, nullable = false)
private Long id;
// ... 생략
}
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class Sogon {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "sogon_id", nullable = false)
private Long id;
// ... 생략
@OneToOne
private MySocon mySocon;
}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class MySocon {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "socon_id", updatable = false, nullable = false)
private Long id;
// ... 생략
}