신비한 개발사전
@Embedded, @Embeddable로 객체지향적인 JPA 엔티티 설계하기 본문
JPA를 사용해보면서 엔티티라는 개념에 익숙해질 때쯤, "DB에 의존적인 설계"라는 표현을 접하게 됐다.
@Entity
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
private String street;
private String city;
private int zip;
}
생각해보니 예시의 User 엔티티는 데이터베이스 테이블의 칼럼과 정확히 일치하도록 필드를 둔 것이고, 따라서 DB에 의존한다는 말이 나온 것이다. JPA가 없는 상황에서 동일한 정보로 User 객체를 만들어야 했다면, 아래처럼 주소와 관련된 값들은 별도의 Address 클래스로 빼도록 설계했을 것이다.
// User 클래스
class User {
private Long id;
private String name;
private int age;
// 주소의 세부적인 정보는 Address의 책임
private Address address;
}
// Address 클래스
class Address {
private String street;
private String city;
private int zip;
}
JPA를 도입하면 위와 같은 객체지향적인 클래스 설계가 불가능한가? 그렇진 않다.
@Embedded, @Embeddable 애노테이션을 사용하면 엔티티의 일부 필드를 클래스로 분리해도 모두 한 테이블의 칼럼으로 생성되도록 구현할 수 있다.
- @Embedded: 분리된 클래스를 저장하는 필드에 적용한다.
- @Embeddable: 분리된 클래스에 적용한다. @Entity는 테이블을 생성하기 때문에, @Embeddable로 대체해야 한다.
@Entity
class User {
// ...중략...
@Embedded
private Address address;
}
@Embeddable // @Entity 대신 사용
class Address {
private String street;
private String city;
private int zip;
}
이렇게 임베딩 방식을 차용하면 자바 코드에서는 Address 객체를 참조할 수 있고, 실제 데이터베이스 테이블에는 address 테이블 없이 street, city, zip 칼럼이 user 테이블에 유지된다.
@Embeddable로 클래스를 분리한 상황에서 연관관계 매핑이 필요하면, 한 엔티티 클래스였을 때 했던 것처럼 매핑이 필요한 필드에 애노테이션을 붙여주면 된다:
@Entity
class User {
// ...중략...
@Embedded
private Address address;
}
@Embeddable
class Address {
private String street;
// User <-> City 간 N:1 연관관계 표현
@ManyToOne
private City city;
private int zip;
}
@Entity
class City {
private String name;
}
참고:
'Backend' 카테고리의 다른 글
Spring REST Docs 적용기 (0) | 2025.06.07 |
---|---|
@Param 및 @PathVariable의 파라미터 관련 에러 원인 및 해결방안 (0) | 2025.05.28 |
@Transactional 유무에 의한 로직 동작 차이 (0) | 2025.05.22 |
RestTemplate vs RestClient (0) | 2025.05.21 |
@DataJpaTest 롤백은 id까지 초기화해주지 않는다 (0) | 2025.05.17 |