java - 带有实体键和实体值的 JPA 映射

标签 java hibernate jpa collections map

关键实体:

@Entity public class KeyEntity
{
    @Id @GeneratedValue(strategy = GenerationType.TABLE)
    public Long id;

    public String handle;

    public boolean equals(Object o) {
        KeyEntity oke = (KeyEntity) o;
        return handle != null ? handle.equals(oke.handle) : oke.handle == null;
    }

    public int hashCode() {
        return handle != null ? handle.hashCode() : 0;
    }
}

值(value)实体:

@Entity public class ValueEntity
{
    @Id @GeneratedValue(strategy = GenerationType.TABLE)
    public Long id;

    @ManyToOne
    public KeyEntity key;

    public String value;

    public boolean equals(Object o) {
        ValueEntity ove = (ValueEntity) o;
        return key != null ? key.equals(ove.key) : ove.key == null;
    }

    public int hashCode() {
        return key != null ? key.hashCode() : 0;
    }
}

容器实体:

@Entity public class ContainerEntity
{
    @Id @GeneratedValue(strategy = GenerationType.TABLE)
    public Long id;

    @OneToMany @MapKey(name = "key")
    public Map<KeyEntity, ValueEntity> values = new HashMap<KeyEntity, ValueEntity>();
}

主要内容:

KeyEntity k1 = new KeyEntity();
k1.handle = "k1";
em.persist(k1);

KeyEntity k2 = new KeyEntity();
k2.handle = "k2";
em.persist(k2);

ValueEntity v1 = new ValueEntity();
v1.key = k1;
v1.value = "v1";
em.persist(v1);

ValueEntity v2 = new ValueEntity();
v2.key = k2;
v2.value = "v2";
em.persist(v2);

ContainerEntity ce = new ContainerEntity();
ce.values.put(k1, v1);
ce.values.put(k2, v2);
em.persist(ce);

// display number of values
System.out.println(ce.values.size());

// create new transaction
em.getTransaction().commit();
em.close();
em = emf.createEntityManager();
em.getTransaction().begin();

// find our container and inspect the number of values
ce = em.find(ContainerEntity.class, ce.id);
System.out.println(ce.values.size());

如果我将多个键值对添加到 ContainerEntity,然后重新加载所述容器,则只会出现一个键值对。如果您查看运行上述 main 函数的输出,首先打印“2”,然后打印“1”。

我可以看出这是因为 KeyEntity.hashCode - 当插入到 HashMap KeyEntity.handlenull,因此所有对都将具有相同的哈希码。 KeyEntity.id 此时已填充 - 如果我将哈希码基于此字段,则一切正常。此外,如果我将 key 更改为 String,它会在调用 hashCode 时及时加载。

我如何更改 ContainerEntity 中的映射,以便 KeyEntity.handle 在放置在 map 中时加载,因此 hashCode 可以用它吗?

最佳答案

参见 herehere :

... As Mike points out, @MapKey was only intended by the spec for the case Map<Basic, Entity>, not for Map<Basic, Embeddable>. The correct annotation for embeddable values would be.

I.E,它的目的是键应该是一个简单的基本类型(这意味着不是一个实体或可嵌入的)和一个实体的值。如果值是基本类型,@ElementCollection 就可以。

但是,您需要的是键是实体类型,在这种情况下,您就不走运了。

正如您已经说过的,如果您将 key 更改为 String,一切都很好,所以我建议您这样做。

关于java - 带有实体键和实体值的 JPA 映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8733190/

相关文章:

Java:从同一类引用 ArrayList<Objects> 的对象

sql - 映射用 Hibernate 返回表的 postgres 函数

java - Hibernate + spring获取最新的lazy 1 to N属性值

java - 使用自定义单元格编辑器删除 JTable 行

java - 自动装箱/拆箱 java Long 类型作为返回值时出现意外的 NullPointerException

java - 如何避免通过 Java 在数据库中重复插入?

java - 事务未成功启动(而 tx.commit() 被 if 条件包围)

Java EE 命名查询连接

java - 如何计算 QueryDSL 中结果组的数量?

java - 如何在收到短信时发送回复短信?