如何在休眠状态下映射Map <string,list <string =“” >>

时间:2019-04-18 14:36:51

标签: java postgresql hibernate spring-data-jpa

我当前正在使用Spring Data JPA,我想映射一个属性

@Entity
public class Outer {
    ...
    Map<String, List<String>> typesToCategories;
}

假设我有一个表outerouter_type_category。第一个很简单:只有列outer_id与之相关

CREATE TABLE outer_types_categories ( 
    id        uuid                        NOT NULL,
    outer_id  uuid                        NOT NULL,
    type      character varying(128)      NOT NULL,
    category  character varying(128)      NOT NULL,
    ...
 )

我应该使用哪个注释(如果可能的话)将此表映射到地图上?

我尝试使用此

    @ElementCollection
    @CollectionTable(name = "outer_type_category", joinColumns = [JoinColumn(name = "outer_id")])
    @MapKeyColumn(name = "type")
    @Column(name = "category")
    Map<String, List<String>> typesToCategories;

但是最后我看到一个异常:

Caused by: org.hibernate.MappingException: Could not determine type for: java.util.List, at table: outer_type_category, for columns: [org.hibernate.mapping.Column(category)]

我忘记了什么吗?

1 个答案:

答案 0 :(得分:0)

JPA指出

  

实体或可嵌入类的持久字段或属性可以   对应于基本类型或可嵌入类的集合   (“元素收集”)。

(JPA 2.2规范,第2.6节;已添加重点)

java.util.List既不是基本类型也不是可嵌入类,因此它不在元素集合的允许元素类型中。而且,JPA继续说

  

元素中包含的可嵌入类[...]   集合不得包含元素集合

,因此即使将List替换为可嵌入的类也无法为您提供一种合适的机制来映射您描述的结构。如果您根本不愿意或无法更改数据库结构,那么我认为您无法以与您所描述的方式类似的方式来映射表。

如果至少可以向数据库中添加一个新表,则可以引入一个新实体,该实体表示映射中的一个条目,例如OuterType,该实体具有映射到outer_types_categories表的元素集合。它可能需要具有一个与(outer_id, type)相对应的复合ID。即使这样,也需要设置数据库端来自动将值分配给收集表的id列(除非您可以删除该列,但实际上这对您的明显目的没有用) ,因为元素集合的成员不是实体,因此JPA不会为它们分配ID。此外,(在JPA方面)具有既是复合主键又是相关实体的外键的一部分的列(在这方面是很麻烦的)。

如果您有更大的自由来修改数据库结构,那么我将使用标准的,代理ID和与OuterType的双向一对一关系来设置上述Outer实体,表示在Outer上作为地图。使用默认映射策略在OuterType中设置一个包含类别字符串的元素集合,该策略将在集合表中使用OuterType的(代理)ID,并且既不使用其“类型”也不使用其“ outer_id”。