@ElementCollection + @CollectionTable vs @OneToMany

이승원·2025년 3월 10일

📌@ElementCollection


@ElementCollection은 엔티티의 필드가 기본값(Primitive Type, Wrapper Class) 또는 Embeddable 타입(내장 타입)인 컬렉션일 경우, 이를 별도의 테이블에 저장하기 위해 사용된다.
일반적으로 단순 값 타입의 리스트(Set, List, Map 등)를 저장할 때 유용하다.


📌 특징


  • 별도의 엔티티(Entity) 없이 컬렉션을 테이블에 저장 가능

  • @OneToMany와 달리 FK를 가지는 별도 엔티티를 만들지 않아도 됨

  • 기본값 타입(예: String, Integer)이나 @Embeddable 타입과 함께 사용 가능

  • 컬렉션 데이터를 저장하는 테이블을 직접 지정하지 않으면 기본적으로 {엔티티명}_{컬렉션필드명} 형태로 자동 생성됨


📌@CollectionTable


@CollectionTable은 @ElementCollection이 적용된 컬렉션 데이터를 저장할 테이블을 명시할 때 사용된다.


📌 특징


  • 컬렉션을 저장하는 테이블명과 외래키(FK) 이름을 지정할 수 있음
  • @JoinColumn을 사용하여 FK 이름을 변경 가능

import jakarta.persistence.*;
import java.util.List;

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

    private String name;

    @ElementCollection  // 값 타입 컬렉션
    @CollectionTable(name = "user_addresses", joinColumns = @JoinColumn(name = "user_id"))
    @Column(name = "address")  // 컬럼명 지정
    private List<String> addresses;

    // Getter, Setter
}

📌 설명


  • @ElementCollection을 사용하여 addresses(주소 목록)를 별도의 테이블(user_addresses)에 저장
  • @CollectionTable(name = "user_addresses")를 통해 테이블 이름을 user_addresses로 지정
  • @JoinColumn(name = "user_id")을 통해 외래키 컬럼 이름을 user_id로 지정
  • @Column(name = "address")을 통해 컬렉션에 저장될 값 컬럼명을 address로 지정

📌@Embeddable 타입 컬렉션 저장


  • 기본값 타입이 아니라, 여러 속성을 가진 객체 리스트를 저장해야 할 때는 @Embeddable을 활용할 수 있다.

import jakarta.persistence.*;

@Embeddable
public class Address {
    private String city;
    private String street;

    // 기본 생성자, Getter, Setter
}

import jakarta.persistence.*;
import java.util.List;

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

    private String name;

    @ElementCollection
    @CollectionTable(name = "customer_addresses", joinColumns = @JoinColumn(name = "customer_id"))
    private List<Address> addresses;

    // Getter, Setter
}

📌@OneToMany


  • “하나(A)가 여러 개(B)를 가질 수 있다”라는 관계를 표현
  • 주로 부모-자식 관계에서 사용됨
  • 연관된 엔티티 리스트(Collection)를 저장할 수 있음

📌예제: 회원(User)가 여러 개의 게시글(Post)를 작성할 수 있음

@Entity
public class User {
    @Id @GeneratedValue
    private Long id;
    
    private String name;

    @OneToMany(mappedBy = "user")  // User(1) → Post(N) 관계
    private List<Post> posts = new ArrayList<>();
}
@Entity
public class Post {
    @Id @GeneratedValue
    private Long id;
    
    private String title;

    @ManyToOne  // 반대편에서 ManyToOne 관계 설정
    @JoinColumn(name = "user_id")
    private User user;
}

📌 설명

•	User(1) - Post(N) 관계이므로 @OneToMany 사용
•	mappedBy = "user" → 연관 관계의 주인은 Post.user 필드
•	Post 엔티티에서 @ManyToOne을 사용해 User를 참조함

📌@OneToMany에서 mappedBy 속성

  • @OneToMany는 반대쪽(@ManyToOne)이 연관관계의 주인이 되어야 함
  • mappedBy를 사용하지 않으면 중간 테이블이 자동 생성되므로 조인 컬럼을 직접 설정하려면 mappedBy를 사용해야 함

📌정리


  • @ElementCollection: 값 타입 컬렉션을 저장할 때 사용

  • @CollectionTable: 컬렉션을 저장할 테이블을 명시할 때 사용

  • @OneToMany와는 다르게 별도의 엔티티 없이 컬렉션 테이블을 생성

  • 컬렉션 데이터 변경 시 성능 이슈가 있을 수 있으므로, 자주 변경되는 데이터는 @OneToMany가 더 적절

0개의 댓글