본문 바로가기

Spring/Spring JPA

@Embedded, @Embeddable 간단하게

@Embedded는 JPA(Java Persistence API)에서 객체 지향적인 데이터 모델링을 지원하기 위해 사용되는 어노테이션입니다. 이는 엔티티 클래스 내에 값 타입(Value Type) 객체를 포함(Embed)하여, 해당 객체의 속성들을 데이터베이스 테이블의 컬럼으로 매핑할 수 있게 해줍니다.

 

1. Embedded의 기본 개념

  • Embedded(포함):
    JPA 엔티티의 필드로 또 다른 객체(값 타입 객체)를 포함시킬 때 사용합니다.
  • 주요 어노테이션:
    • @Embedded: 값 타입 객체를 엔티티에 삽입할 때 사용.
    • @Embeddable: 값 타입 객체로 사용할 클래스를 정의할 때 사용.

2. Embedded와 Embeddable의 관계

@Embedded와 @Embeddable은 항상 같이 사용됩니다.

@Embeddable

  • 값 타입 객체로 사용할 클래스를 정의할 때 사용.
  • 독립적인 엔티티가 아니며, 다른 엔티티에 포함됩니다.
  • 데이터베이스 테이블에서는 포함된 엔티티의 필드들이 그대로 컬럼으로 매핑됩니다.

@Embedded

  • 엔티티 클래스의 필드에 @Embeddable로 정의된 클래스를 삽입할 때 사용.
  • 기본적으로 @Embedded는 생략 가능(암시적으로 동작).

 

3. Embedded의 동작 원리

@Embedded로 매핑된 값 타입의 필드들은 해당 필드에 포함된 객체의 모든 속성이 엔티티의 컬럼으로 분해되어 데이터베이스에 저장됩니다. 이를 통해 엔티티 클래스가 더 구조적이고 모듈화될 수 있습니다.

예제

1. Address라는 값 타입 정의

import jakarta.persistence.Embeddable;

@Embeddable
public class 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
}

 

2. User 엔티티에서 Address 포함

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Embedded;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Embedded
    private Address address;

    // Getter, Setter
}

 

3. 결과적으로 매핑되는 테이블

User 엔티티는 아래와 같이 테이블로 변환됩니다.

 

id name city street zipCode
1 John Doe Seoul Gangnam 12345
2 Jane Smith New York Manhattan 54321

 

4. Embedded의 활용 이유

  1. 객체지향적인 설계
    • 데이터베이스 테이블에 컬럼을 나열하는 대신, 객체를 이용해 관련 데이터를 묶어 구조적으로 표현할 수 있습니다.
  2. 재사용성
    • @Embeddable로 만든 값 타입 클래스는 여러 엔티티에서 재사용할 수 있습니다.
    • 예를 들어, Address, ContactInfo 같은 공통 정보를 재사용 가능.
  3. 가독성 및 유지보수성
    • 엔티티 클래스에서 반복적으로 사용되는 속성을 제거하고, 이를 별도의 값 타입 객체로 정의해 코드 가독성을 높입니다.
  4. 캡슐화
    • 값 타입으로 묶어서 관련 속성을 하나의 객체로 관리할 수 있어 응집도가 높아집니다.

 

 

5. Embedded의 활용 예제

5.1. 단일 값 타입 매핑

Employee 엔티티와 ContactInfo 값 타입

@Embeddable
public class ContactInfo {
    private String email;
    private String phone;

    // 기본 생성자
    public ContactInfo() {}

    public ContactInfo(String email, String phone) {
        this.email = email;
        this.phone = phone;
    }

    // Getter, Setter
}

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Embedded
    private ContactInfo contactInfo;

    // Getter, Setter
}

 

5.2. 복합 값 타입 매핑

동일한 값 타입을 여러 필드로 사용

@Entity
public class Company {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "city", column = @Column(name = "office_city")),
        @AttributeOverride(name = "street", column = @Column(name = "office_street")),
        @AttributeOverride(name = "zipcode", column = @Column(name = "office_zipcode"))
    })
    private Address officeAddress;

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "city", column = @Column(name = "home_city")),
        @AttributeOverride(name = "street", column = @Column(name = "home_street")),
        @AttributeOverride(name = "zipcode", column = @Column(name = "home_zipcode"))
    })
    private Address homeAddress;

    // Getter, Setter
}

 

 

6. Embedded의 주의사항

  1. 값 타입은 불변 객체로 설계
    • 값 타입은 공유 참조로 인해 여러 엔티티에서 값이 변경될 위험이 있습니다.
    • 따라서 Setter를 제거하고, 생성자만을 통해 초기화하도록 설계하는 것이 좋습니다.
  2. 테이블 컬럼 이름 충돌 가능성
    • 동일한 값 타입을 여러 필드에서 사용할 경우 컬럼 이름이 충돌할 수 있습니다. 이를 해결하려면 @AttributeOverrides를 사용해야 합니다.
  3. 별도 테이블 생성 불가
    • @Embeddable은 독립적인 테이블로 매핑되지 않으며, 항상 포함된 엔티티의 테이블에 속합니다.
  4. 직렬화 필요
    • @Embeddable 클래스는 직렬화 가능(Serializable)하도록 설계하는 것이 일반적입니다.

 

7. 결론

  • JPA의 **@Embedded**는 객체지향적 설계를 데이터베이스에 잘 매핑하기 위한 강력한 도구입니다.
  • 재사용성, 가독성, 유지보수성을 높이고, 공통 데이터를 처리하거나 복잡한 엔티티 설계를 단순화하는 데 유용합니다.
  • 그러나 설계 시 불변 객체로 구현하고, 컬럼 충돌 문제를 주의해야 합니다.

'Spring > Spring JPA' 카테고리의 다른 글

배치 쿼리의 성능 이슈 원인 간단하게  (0) 2025.01.15
영속성 컨텍스트(Persistence Context)  (0) 2025.01.07
@Converter 간단하게  (1) 2025.01.07
Native Query  (1) 2025.01.06
JPQL 간단히  (0) 2025.01.06