본문 바로가기
개발/Java

[JPA] Jakarta Spec(JSR 338) - (4)Map Collections

by Mingvel 2023. 9. 3.

[이전 글]

[JPA] Jakarta Spec(JSR 338) - (1)Entity, Field, Access Type

[JPA] Jakarta Spec(JSR 338) - (2)기본 키(PK) 및 Entity ID

[JPA] Jakarta Spec(JSR 338) - (3)Embeddable Classes

 

Jakarta EE 로고

JPA에서의 Map Collection

Entity 클래스 내부에서 속성의 Collection이나, Entity 간의 관계를 표현할 때 java.util.Map 컬렉션을 사용할 수 있다

 

Map의 Key와 Value에는 Java 기본 타입, Embeddable 클래스, 또 다른 Entity가 포함될 수 있다

 

(1) Map의 Value가 Java 기본 타입, Embeddable 클래스일 경우엔 @ElementCollection 어노테이션이 사용된다

 

(2) Map의 Value가 또 다른 Entity일 경우, 이는 관계(Relation) 매핑으로 @OneToMany , @ManyToMany 어노테이션이 사용된다

 

Map 형태로 표현되는 양방향 관계는 관계의 한쪽에서만 Map을 사용할 수 있다

 

 

Map Key

  • Map의 Key가 Java 기본 타입일 경우, @MapKeyColumn 어노테이션을 사용하여 지정한 컬럼으로 매핑시킬 수 있다
    • Key가 Java 기본 타입이지만 @MapKeyColumn 어노테이션을 명시하지 않을 경우, 기본 값은 속성의 이름이다. (snake strategy 사용)
  • Map의 Key가 Embeddable 클래스일 경우, Embeddable 클래스 내부 속성에 명시한 @Column 이름을 따른다
    • @AttributeOverride와 @AttributeOverrides 어노테이션은 Embeddable 클래스 내부 매핑을 Override 할 수 있다 (Owner에서 명시)
    • 위와 같이 Embeddable 클래스를 Map의 Key로 매핑하는 경우, Embeddable 클래스는 hashCode, equals 메서드를 반드시 구현해야 한다
  • Map의 Key가 Entity 클래스일 경우, @MapKeyJoinColumn 혹은 @MapKeyJoinColumns 어노테이션으로 Key 매핑을 수행한다
    • 위 어노테이션의 name 속성으로 FK Join 컬럼명을 지정할 수 있다
    • 위 어노테이션의 name 속성을 사용하지 않고, Key에 해당하는 Entity가 단일 기본키를 사용한다면 default 값으로 해당 기본키로 FK Join 매핑된다
  • Map이 generic Type이 아닌 경우 한드시 @MapKeyClass 어노테이션을 명시하여, 어떤 타입으로 매핑되어야 하는지 명시해 주어야 한다
  • OneToMay 연관관계 매핑의 주인인 Entity에서 @MapKey 어노테이션을 명시하여 매핑할 수 있다
    • MapKey 어노테이션으로 명시한 Map의 Key 값이, 주인 Entity의 PK 값이 된다

 

@MapKeyColumn 사용 예시

@Entity
public class User {
    @Id
    private Long id;

    @ElementCollection
    @MapKeyColumn(name="phone_type") // Map의 Key를 phone_type 컬럼에 매핑
    private Map<String, String> phones = new HashMap<>();  // Key: phone type, Value: phone number
}

 

 

@MapKeyJoinColumn 사용 예시

@Entity
public class VideoStore {
    @Id
    int id;

    // ...

    @ElementCollection
    @CollectionTable(name="INVENTORY", joinColumns=@JoinColumn(name="STORE"))
    @Column(name="COPIES_IN_STOCK")
    @MapKeyJoinColumn(name="MOVIE", referencedColumnName="ID")
    Map<Movie, Integer> videoInventory;

    // ...
}

@Entity
public class Movie {
    @Id
    long id;

    // ...
}

 

@MapKey 사용 예시

@Entity
public class Department {

    // ...
    
    @Id
    private Integer id;

    @OneToMany(mappedBy="department")
    @MapKey // map key is primary key
    public Map<Integer, Employee> getEmployees() { ... }

    // ...
}

@Entity
public class Employee {

    // ...

    @Id public Integer getEmpId() { ... }
    @ManyToOne
    @JoinColumn(name="dept_id")
    public Department getDepartment() { ... }

    // ...
}

 

Map Values

  • Map의 Value에 해당하는 타입이 Java 기본 타입이거나 Embeddable 클래스일 경우, collection table을 사용하여 맵을 매핑 한다
  • Map에 Generic type이 사용되지 않았을 경우, @ElementCollection 어노테이션의 `targetClass` 속성을 사용하여 타입을 명시해 줘야 한다 (필수)
  • Map의 Value에 대한 매핑 기본 값은 @CollectionTable 어노테이션의 기본 규칙을 따른다
  • @Column 어노테이션을 명시하여 Java  기본 타입의 Map의 Value에 대한 매핑을 정의할 수 있다
  • Map의 Value가 Embeddable 클래스일 경우, @AttributeOverride(s) 혹은 @AssociationOverride(s) 어노테이션으로 매핑을 정의할 수 있다
  • Map의 Value가 또 다른 Entity일 경우 join table이 사용된다
    • 기본적으로 ManyToMany 관계 혹은 OneToMany 단방향 관계를 매핑한다
    • 만약 관계가 OneToMany 양방향, ManyToOne 관계일 경우, Map의 Value에 해당하는 Entity의 테이블에 매핑된다
  • Map에 Java generic Type이 사용되지 않았을 경우 @OneToMany 혹은 @ManyToMany 어노테이션의 `targetEntity` 속성에 대상 데이터 타입을 명시해줘야 한다
반응형

댓글