2012-01-04 22 views
6

chiave di entità:JPA Mappa w/Entità chiave e valore di entità

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

Valore Entità:

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

contenitore di entità:

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

principale:

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

Se aggiungo più coppie chiave-valore a ContainerEntity e quindi ricarico il contenitore, sarà presente una sola coppia chiave-valore. Se si guarda l'output di eseguire la funzione principale sopra, viene stampato prima '2', seguito da '1'.

posso vedere che questo è causa di KeyEntity.hashCode - quando si inserisce nel HashMapKeyEntity.handle è null, quindi tutte le coppie avranno lo stesso codice hash. KeyEntity.id viene popolato a questo punto - se il codice hash viene disattivato da questo campo, tutto funziona. Inoltre, se cambio la chiave in modo che sia String, viene caricata in tempo per le chiamate a hashCode.

Come è possibile modificare le mie mappature in ContainerEntity in modo che KeyEntity.handle venga caricato quando viene inserito all'interno della mappa, quindi hashCode può utilizzarlo?

+0

Trovo che questo sia piuttosto strano. Perché il riferimento a gestire non fa scattare un carico dal database? Apprezzo che KeyEntity venga caricato pigramente, ma l'accesso a un campo dovrebbe svegliarlo! –

risposta

3

Vedi here e here:

... Come Mike sottolinea, @MapKey era destinato esclusivamente dalle specifiche per la caso Mappa < di base, Entità >, non per Map < di base, Embeddable > . L'annotazione corretta per i valori incorporabili sarebbe.

I.E, è inteso che la chiave dovrebbe essere un tipo di base semplice (che non è un'entità o incorporabile) e il valore un'entità. Se il valore è un tipo base, lo farebbe @ElementCollection.

Tuttavia, ciò di cui hai bisogno è che la chiave sia di tipo entità e, in questo caso, sei sfortunato.

Come già detto, se si modifica la chiave su String, tutto è a posto, quindi ti suggerisco di farlo.

+0

tanto quanto speravo in una soluzione migliore, non sembra che ce ne sia una. Sto duplicando l'handle String in ValueEntity, quindi posso utilizzarlo come chiave della mappa – rhollencamp

Problemi correlati