【发布时间】: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。注意:你不需要@MapKeyClass和targetEntity输入 java.util.Map -
我正在使用@MapKeyClass,因为类型化的 java.util.Map 是使用实体的接口类型化的。您需要 MapKeyClass 来告诉要实例化哪个实体类。
-
正如我在原始问题中所说,我尝试使用@ManyToMany,但当键或值是实体时,它仍然不会覆盖列名
标签: java hibernate jpa dictionary annotations