"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."
www.inflearn.com/course/ORM-JPA-Basic#
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그
www.inflearn.com
임베디드 타입을 사용하는 방법
JPA 에서는 @Embeddable 어노테이션(값 타입을 정의하는 곳에 표시), @Embedded 어노테이션 (값 타입을 사용하는 곳에 표시) 을 만들어서 사용한다.
(기본 생성자 - default constructor 를 필수로 생성해줘야 한다.)
* 임베디드 타입의 장점?
- 재사용이 가능하다.
- 코드의 응집도가 높다.(Period, Address 와 같은 클래스의 경우 Period.isWork() 처럼 해당 값 타입만 사용하는 의미 있는 메소드를 만들어 낼 수 있다. - 상당히 객체지향적임)
- 임베디드 타입 또한 값 타입이기 때문에 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 Entity 에 생명주기를 의존한다.
* 임베디드 타입과 테이블 매핑
- DB 입장에서는 컬럼이 바뀔것이 없다.
- 값 타입을 쓰든 안 쓰든, 임베디드 타입을 쓰든 안 쓰든, 테이블은 똑같이 생성된다.
- 테이블 입장에서는 데이터를 잘 관리하는게 목적이기 때문에 기존 설계대로 하면 된다.
- 하지만 객체는 데이터 뿐 만 아니라 메소드와 같은 기능까지 다 들고 있다, 그렇기 때문에 묶었을 때 가져올 수 있는 이득이 많다.
아래의 코드를 살펴보자.
- Member.java
@Entity
public class Member{ // BaseEntity 상속 제거
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
private LocalDateTime startDate;
private LocalDateTime endDate;
private String city;
private String street;
private String zipcode;
}
임베디드 타입을 사용하지 않고 기존과 같이 코드를 작성하면 아래와 같은 hibernate SQL 을 얻을 수 있다.
- hibernate SQL
Hibernate:
create table Member (
MEMBER_ID bigint not null,
city varchar(255),
endDate timestamp,
startDate timestamp,
street varchar(255),
USERNAME varchar(255),
zipcode varchar(255),
TEAM_ID bigint,
primary key (MEMBER_ID)
)
여기서 비슷한 속성들을 임베디드 타입을 통해 하나로 묶어보자.
Period, Address 클래스를 생성하여 비슷한 속성들을 하나로 묶는다.
- Period.java
@Embeddable // 값 타입을 정의하는 곳에 선언하는 어노테이션
public class Period {
//Period
private LocalDateTime startDate;
private LocalDateTime endDate;
public Period() { // 기본 생성자는 필수로 있어야 한다.
}
public Period(LocalDateTime startDate, LocalDateTime endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
// Getter, Setter
}
- Address.java
@Embeddable
public class Address {
//Address
private String city;
private String street;
private String zipcode;
public Address() {
}
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
// Getter, Setter
}
이후 Member.java 에서 비슷한 속성끼리 묶어놓은 임베디드 타입을 사용하기 위해 아래와 같이 코드를 작성해주자.
- Member.java
@Entity
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@Embedded // 값 타입을 사용하는 곳에 선언하는 어노테이션
private Period workPeriod;
@Embedded
private Address homeAddress;
// Getter, Setter
}
이후 애플리케이션을 실행해보면 출력되는 hibernate SQL 을 통해 아래와 같이 테이블이 생성되는 것을 알 수 있다.
- hibernate SQL
Hibernate: // 임베디드 타입을 사용하기 전과 똑같은 구조로 테이블이 생성된다.
create table Member (
MEMBER_ID bigint not null,
city varchar(255),
street varchar(255),
zipcode varchar(255),
USERNAME varchar(255),
endDate timestamp,
startDate timestamp,
TEAM_ID bigint,
primary key (MEMBER_ID)
)
이렇게 임베디드 타입의 클래스가 만들어지고 나면 클래스 내부의 속성들을 사용하는 메소드 들을 생성하여 응집력을 더욱 높여줄 수 있다.
이제 실질적으로 JpaMain.java 에서 임베디드 타입 클래스 들을 사용해보자.
- JpaMain.java
Member member = new Member();
member.setUsername("hello");
member.setHomeAddress(new Address("city", "street", "10000"));
member.setWorkPeriod(new Period());
em.persist(member);
- hibernate SQL
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(city, street, zipcode, USERNAME, endDate, startDate, MEMBER_ID)
values
(?, ?, ?, ?, ?, ?, ?)
위의 hibernate SQL 을 보면 데이터가 정상적으로 테이블에 insert 되는 것을 확인할 수 있다.
그렇다면 왜 임베디드 타입을 활용해 주는 것이 좋을까?
- 임베디드 타입은 Entity 의 값일 뿐이다.
- 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 서로 같다.(중요한 특징)
* 임베디드 타입을 사용할 때와, 그렇지 않을 때의 차이점?
- 임베디드 타입을 사용하면 객체와 테이블을 아주 세밀하게(find - grained) 매핑하는 것이 가능하다.
예시 : 회원 Entity 는 이름, 근무 기간, 집 주소를 가진다 (이와 같이 추상화를 하는 방식으로 설계하면 설명하기도 좋고 모델링도 깔끔하게 딱 떨어진다.)
- 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수 보다 클래스의 수가 더 많다.
다음 글에선 임베디드 타입과 연관관계에 대해 알아보자.
'JPA' 카테고리의 다른 글
값 타입 - 불변 객체와 값 타입 비교(1) (0) | 2020.10.21 |
---|---|
값 타입 - 기본 값 타입, 임베디드 타입(3) (0) | 2020.10.21 |
값 타입 - 기본 값 타입, 임베디드 타입(1) (0) | 2020.10.21 |
실전예제 5 - 프록시 및 연관관계 (0) | 2020.10.17 |
영속성 전이(CASCADE) 와 고아 객체 - 2 (0) | 2020.10.17 |