【问题标题】:Key & value column name overrides when mapping java.util.Map with JPA annotations使用 JPA 注释映射 java.util.Map 时键和值列名称覆盖
【发布时间】:2014-07-31 01:55:47
【问题描述】:

我正在研究使用 Hibernate 4.1.9 和 JPA 注释对地图进行注释的不同方式。

如果我想存储一个 Map,其中键是实体值的属性,标记看起来像这样

    @OneToMany(mappedBy = "deptById", targetEntity = com.demo.impls.Employee.class)
    @MapKey(name = "entityId")
    private Map<Long, Employee> employeesById;

请注意,上述标记不会创建连接表,但 Map 在运行时通过查询返回,因此 Map 是动态的,您不必在 Java 中将元素添加到地图中即可返回通过查询。

现在我希望 Map 的内容反映应用程序添加到 Map 中的内容,而不是执行动态查询。

我要存储 4 种地图

    private Map<String, String> map0;
    private Map<String, Entity> map1;
    private Map<Entity, String> map2;
    private Map<Entity, Entity> map3;

在这些情况下,键 & 和值之间没有任何关系,与持有实体也没有任何关系。 我必须能够指定连接表的名称以及键和值的列名。

我已经尝试了以下

@Entity
public class Department {
    @ElementCollection
    @CollectionTable(name = "TEST_MAP0")
    @Column(name="value")
    @MapKeyColumn(name="Key")
    private Map<String, String> map0;

    @ElementCollection(targetClass = com.demo.bb.impls.Employee.class)
    @CollectionTable(name = "TEST_MAP1")
    @Column(name="value")
    @MapKeyColumn(name="Key")
    private Map<String, Employee> map1;

    @ElementCollection
    @MapKeyClass(value = com.demo.bb.impls.Employee.class)
    @CollectionTable(name = "TEST_MAP2")
    @Column(name="value")
    @MapKeyColumn(name="Key")
    private Map<Employee, String> map2;

    @ElementCollection(targetClass = com.demo.bb.impls.ParkingSpace.class)
    @MapKeyClass(value = com.demo.bb.impls.Employee.class)
    @CollectionTable(name = "TEST_MAP3")
    @Column(name="value")
    @MapKeyColumn(name="Key")
    private Map<Employee, ParkingSpace> map3;

Case 0 Map 工作正常,生成的连接表包含 DEPARTMENT、VALUE、KEY 列

其他三种情况在您可以将数据存储在表中并在 Java 中使用相关的键/值查询表并返回预期结果的情况下工作 - 即它确实使用 @ElementCollection 处理存储实体

但是当键或值是实体时,会忽略使用 @Column(name="value") 和 @MapKeyColumn(name="key") 覆盖的列名。

我尝试过如下使用@ManyToMany注解

    @ManyToMany(targetEntity = com.demo.bb.impls.Employee.class)
    @JoinTable(name = "TEST_MAP1_B")
    @Column(name="value")
    @MapKeyColumn(name="Key")
    private Map<String, Employee> map1_B;

    @ManyToMany(targetEntity = com.demo.bb.impls.ParkingSpace.class)
    @MapKeyClass(value = com.demo.bb.impls.Employee.class)
    @JoinTable(name = "TEST_MAP3_B")
    @Column(name="value")
    @MapKeyColumn(name="Key")
    private Map<Employee, ParkingSpace> map3_B;

但再次忽略键和值列名称覆盖。有谁知道强制这些列名覆盖的方法。

提前谢谢...

UPDATE....在查看@wypieprz 的响应后,我想我知道正确的注释,允许您在 Map 由具有实体值的基本键控时指定值和键的列名。

通过以下方式

    @ManyToMany(targetEntity = com.demo.bb.impls.Employee.class)
    @JoinTable(name = "TEST_MAP1", inverseJoinColumns=@JoinColumn(name="VALUE"))
    @MapKeyColumn(name="KEY")
    private Map<String, Employee> map1;

使用 inverseJoinColumn 我可以指定值列名称。

但如果键是实体,我还没有找到指定键列名称的方法。正如文档所说,@MapKeyColumn“指定映射键为基本类型的映射键列的映射”

当键是实体且值是基本值时,我也不确定要使用的注释。使用 ManyToMany 是行不通的,我想我可能不得不使用 ElementCollection 但我还是找不到指定键列名称的方法。

更新 2... 感谢 Peter Halicky 的解决方案。

总而言之,在每个案例中命名所有 3 列,您需要执行类似的操作。

@ElementCollection
@CollectionTable(name = "TEST_MAP0", joinColumns = @JoinColumn(name = "DEPARTMENT"))
@Column(name = "value")
@MapKeyColumn(name = "key")
private Map<String, String> map0;

@ManyToMany(targetEntity = com.hibernate.elephants.Employee.class)
@JoinTable(name = "TEST_MAP1", joinColumns = @JoinColumn(name = "DEPARTMENT"), inverseJoinColumns = @JoinColumn(name = "value"))
@MapKeyColumn(name = "key")
private Map<String, Employee> map1;

@ElementCollection
@CollectionTable(name = "TEST_MAP2", joinColumns = @JoinColumn(name = "DEPARTMENT"))
@MapKeyClass(value = com.hibernate.elephants.Employee.class)
@MapKeyJoinColumn(name = "key")
@Column(name = "value")
private Map<Employee, String> map2;

@ManyToMany(targetEntity = com.hibernate.elephants.ParkingSpace.class)
@JoinTable(name = "TEST_MAP3", joinColumns = @JoinColumn(name = "DEPARTMENT"), inverseJoinColumns = @JoinColumn(name = "value"))
@MapKeyClass(value = com.hibernate.elephants.Employee.class)
@MapKeyJoinColumn(name="key")
private Map<Employee, com.hibernate.elephants.ParkingSpace> map3;

注意有两种情况被指定为ElementCollection,但是值是另一个Entity的两种情况需要使用ManyToMany。

【问题讨论】:

  • @ElementCollection@CollectionTable 应该只用于基本类型和嵌入,对于实体使用 @OneToMany@ManyToMany。注意:你不需要 @MapKeyClasstargetEntity 输入 java.util.Map
  • 我正在使用@MapKeyClass,因为类型化的 java.util.Map 是使用实体的接口类型化的。您需要 MapKeyClass 来告诉要实例化哪个实体类。
  • 正如我在原始问题中所说,我尝试使用@ManyToMany,但当键或值是实体时,它仍然不会覆盖列名

标签: java hibernate jpa dictionary annotations


【解决方案1】:

我使用实体作为 Map 的键,如下所示。使用 @MapKeyJoinColumn 注释,我可以指定作为地图键的列的名称。这在 Hibernate 上对我有用,不确定其他 JPA 实现会做什么,但肯定值得尝试。

@ElementCollection
@CollectionTable(name="breed_descriptions", joinColumns={ @JoinColumn(name="breed") })
@Column(name="description")
@MapKeyJoinColumn(name="language")
private Map<Language, String> descriptions = new HashMap<>();

【讨论】:

    猜你喜欢
    • 2017-06-06
    • 2012-09-05
    • 2012-07-22
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2010-10-22
    • 1970-01-01
    相关资源
    最近更新 更多