当前位置: 首页 > 面试题库 >

使用JPA批注映射java.util.Map时,键和值列名称将被覆盖

施兴言
2023-03-14
问题内容

我正在研究使用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中将html" target="_blank">元素添加到Map中即可通过查询返回它们。

现在,我希望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;

情况0映射工作正常,并且生成的联接表具有列DEPARTMENT,VALUE,KEY

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

但是,当键或值是Entity时,将忽略使用@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;

但是,同样会忽略键和值列名称的替代。有人知道强制这些列名覆盖的方法吗?

提前致谢…

更新…。查看来自@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“指定了地图键为基本类型的地图的键列的映射”

我也不确定当键是Entity且值是基本值时要使用的注释。使用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。


问题答案:

我将实体用作地图的键,如下所示。使用@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<>();


 类似资料:
  • 问题内容: 我在类型为char(7)的MySQL表中的“语言”列上遇到JPA /hibernate映射问题。在我的实体中,为该字段生成的代码为: 这会在运行时导致以下异常: 提前致谢 ! J.P 问题答案: 尝试这个: 看看是否可行。

  • 我有两个表:A和B,都有一个复合主键。表B的PK也是表a主键的外键。 当我试图获取映射表B的类的实例时,我得到了以下异常: org.hibernate.TypeMismatchException 这两个类都位于package:com.cairone.ejemple01.entities 完整的日志输出为: 2016-09-21 12:28:24.505错误8568--[main] O.S.Boot

  • 问题内容: 我正在使用Hibernate 3.3和PostgreSQL 8.x,并希望使用Hibernate批注来映射不是主键的自动增量列。 只要该列是由数据库而不是由Hibernate自动递增的,则在Postgres中使用SERIAL类型或序列映射该列都没有关系。我尝试了以下映射,但它们始终生成空的orderId。 我将不胜感激。 谢谢 问题答案: 以下映射应该可以正常工作: 但是请注意,刷新会

  • 如果所有的命名都是按照 Mapper 的映射来操作的,那当然是最理想的。但是如果碰到某个表名或者某个字段名跟映射规则不匹配时,我们就需要别的机制来改变。xorm 提供了如下几种方式来进行: 如果结构体拥有 TableName() string 的成员方法,那么此方法的返回值即是该结构体对应的数据库表名。 通过 engine.Table() 方法可以改变 struct 对应的数据库表的名称,通过 s

  • 我的数据库是: 我们可以在Table2中为Table1中的1设置多行。 我的TABLE1实体是: 我的Table1Id类是: 我的TABLE2实体是: 我的Table2Id类是: 当我尝试启动我的tomcat时,我有以下错误: 我尝试使用引用列,主键连接列和许多其他东西,但是通过在互联网上阅读它,它可以解决数据库建模问题。我认为问题是主键和外键在2个表中具有相同的名称,但我可能是错的......我

  • 问题内容: 假设我正在调用一个API,该API以产品的以下JSON响应: 我可以使用Jackson标注来映射产品ID和名称: 然后使用fromJson方法创建产品: 但是,现在我试图弄清楚如何获取品牌名称,这是一个嵌套属性。我希望这样的事情会起作用: 但是,当然没有。有没有一种简单的方法可以使用注释来完成我想要的工作? 我尝试解析的实际JSON响应非常复杂,即使我只需要一个字段,我也不必为每个子节