임베디드 타입
새로운 값 타입을 직접 정의할 수 있다.
주로 기본값 타입을 모아서 만들어서 복합 값 타입이라고도 한다.
신기한 점은, int나 String 같이 추적되는 것이 아니라 바꾸면 끝나는 그런거다.
예시
이렇게 회원 엔티티 있을 때,
뭔가 공통적으로 묶어서 할 수 있다.
예를 들어
이렇게.
아예 주소와 날짜는 묶어서 취급한다.
그냥 클래스 하나 더 만들어서 취급하는 거랑 비슷하긴 하다.
이렇게
임베디드 타입 사용법은
@Embeddable : 값 타입을 정의한 곳
@Embedded : 값 타입을 사용한 곳.
기본 생성자 필수임.
임베디드 타입 장점
재사용 가능
높은 응집도
메소드 만들 수 있음.
임베디드를 포함한 모든 값 타입은, 값타입을 소유한 엔티티의 생명주기에 의존.
엔티티의 생명주기에 의존한다는 것만 빼면
클래스의 장점이랑 같다.
객체지향적 설계가 가능함.
값타입은 엔티티 죽으면 다 죽고 엔티티 생성될 때 값 다 들어오는 그런거임.
테이블 입장에서는 임베디드를 쓰든 안쓰든 똑같고,
객체 입장에서는 테이블이랑 매핑을 해줘야 한다.
코드로 보자면
@Entity
public class Member extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="MEMBER_ID")
private Long id;
private String name;
private LocalDateTime startDate;
private LocalDateTime endDate;
private String city;
private String street;
private String zipcode;
}
여기서 기간과 주소를 따로 묶고 싶다,
@Entity
public class Member extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="MEMBER_ID")
private Long id;
private String name;
@Embedded
private Period period;
@Embedded
private Address address;
}
이렇게 클래스로 만든다.
@Embeddable
public class Period {
private LocalDateTime startDate;
private LocalDateTime endDate;
public Period() {
}
}
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
public Address() {
}
}
클래스 만든 곳에 @Embeddable 해서 이거 임베디드할수 있는 갑타입이라고 표시.(기본생성자는 필수. 그리고 물론 메소드 있어도 됨. )
그리고,
@Embedded
private Address address;
이런 식으로 해서 이거 임베디드된 값이라고 해줌
@Embeddable : 임베비드 정의한 클래스에다 씀.
@Embedded : 임베디드 사용할 곳, 그 필드에다가 씀.
근데 둘 중 한쪽에다만 써도 됨. 근데 두곳에 다 쓰는게 아무래도 명시적이라 들어가서 확인 할 필요가 없어지지.
그리고 만약 임베디드값이 null이면 그 관련 테이블도 다 null 들어감.
여튼 이렇게 하면,
Hibernate:
create table Member (
MEMBER_ID bigint not null,
createdDate timestamp(6),
endDate timestamp(6),
lastModifiedDate timestamp(6),
startDate timestamp(6),
city varchar(255),
name varchar(255),
street varchar(255),
zipcode varchar(255),
primary key (MEMBER_ID)
)
제대로 임베디드 타입 반영해서 테이블이 만들어 짐.
Member member = new Member();
member.setName("memberA");
member.setAddress(new Address("city1", "street1", "zip1"));
member.setPeriod(new Period());
em.persist(member);
tx.commit();
insert도 잘 됨.
임베디드 타입은 하나의 엔티티의 값일뿐임.
임베디드를 사용하던 사용하지 않던 테이블은 똑같음.
잘 설계한 ORM은 매핑한 테이블 수보다 이런 클래스의 수가 더 많음.
그렇다고 너무 다 하려고 하지 말고, 적절히 잘 쓰면 괜찮을 듯. 메소드도 넣을 수 있으니.
임베디드 타입과 연관관계
임베디드는 임베디드를 가질 수 있고,
또 임베디드는 엔티티도 가질 수 있다.
하긴 뭐 임베디드가 값들을 그냥 합쳐서 쓰는거니..
만약 같은 임베디드타입을 복수로 가지고 싶은 경우
@Entity
public class Member extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="MEMBER_ID")
private Long id;
private String name;
@Embedded
private Period period;
@Embedded
private Address homeAddress;
@Embedded
private Address workAddress;
}
이러면 에러남.
이거는 아무래도 임베디드 타입 자체는 같은거라 컬럼명 같다고 오류나는데,
이때는 그럼 직접 컬럼명을 명시해 줘야 함.
@Entity
public class Member extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="MEMBER_ID")
private Long id;
private String name;
@Embedded
private Period period;
@Embedded
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "WORK_CITY")),
@AttributeOverride(name = "street", column = @Column(name = "WORK_STREET")),
@AttributeOverride(name = "zipcode", column = @Column(name = "WORK_ZIP"))
})
private Address workAddress;
}
이렇게 @AttributeOverrides
해서 @AttributeOverride 들을 명시해 줘야 함. { } 중괄호로 묶어서
필드 지정한 다음 컬럼을 다르게 오버라이드 해 줘야 함.
Hibernate:
create table Member (
MEMBER_ID bigint not null,
createdDate timestamp(6),
endDate timestamp(6),
lastModifiedDate timestamp(6),
startDate timestamp(6),
WORK_CITY varchar(255),
WORK_STREET varchar(255),
WORK_ZIP varchar(255),
city varchar(255),
name varchar(255),
street varchar(255),
zipcode varchar(255),
primary key (MEMBER_ID)
)
테이블 이렇게 생성됨.
'JPA > JPA 기본' 카테고리의 다른 글
34. 값타입 비교 (0) | 2023.10.29 |
---|---|
33. 값타입과 불변 객체 (0) | 2023.10.29 |
31. 기본값 타입 (0) | 2023.10.29 |
30. 실전 연관관계 관리 (0) | 2023.10.29 |
29. 영속성 전이와 고아 객체 (0) | 2023.10.28 |