JPA card with entity key and entity value

The main object:

@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; } } 

Container:

 @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>(); } 

Main:

 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()); 

If I add several key-value pairs to ContainerEntity , and then reload the specified container, only one key-value pair will be present. If you look at the result of working on the main function, first type “2” and then “1”.

I see that this is due to KeyEntity.hashCode - when pasting into the HashMap KeyEntity.handle is null , so all pairs will have the same hash code. KeyEntity.id populated at this point - if I base the hash code on this field, everything will work. Also, if I change the key to String , it will be loaded on time for hashCode calls.

How to change my mappings in ContainerEntity so that KeyEntity.handle when it is placed inside the map, so hashCode can use it?

+6
source share
1 answer

Look here and here :

... As Mike points out, @MapKey was for specification only for case Map <Basic, Entity>, not Map <Basic, Embeddable>. The correct annotation for the embedded values ​​will be.

IE, it is assumed that the key should be a simple base type (which means not an entity or an embed), but a value - an entity. If the value is a base type, @ElementCollection will do.

However, you need the key to be an entity type, in which case you are out of luck.

As you said, if you change the key to String , everything will be fine, so I suggest you do it.

+3
source

Source: https://habr.com/ru/post/905133/


All Articles