JPA/JPA 기본

32. 임베디드 타입

sdafdq 2023. 10. 29. 17:35

임베디드 타입

새로운 값 타입을 직접 정의할 수 있다.

주로 기본값 타입을 모아서 만들어서 복합 값 타입이라고도 한다.

신기한 점은, 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