2014-06-10 8 views
6

Sto osservando i diversi modi di annotare le mappe utilizzando Hibernate 4.1.9 & annotazioni JPA.Nome della colonna chiave e valore sovrascrive durante il mapping di java.util.Map con annotazioni JPA

Se voglio conservare una mappa in cui la chiave è un attributo del valore dell'entità del mark up sembra come questo

@OneToMany(mappedBy = "deptById", targetEntity = com.demo.impls.Employee.class) 
    @MapKey(name = "entityId") 
    private Map<Long, Employee> employeesById; 

nota il marchio di cui sopra fino non crea una tabella di join ma la mappa viene restituito tramite una query in fase di esecuzione, quindi la mappa è dinamica e non è necessario aggiungere elementi nella mappa in Java affinché vengano restituiti dalla query.

Ora voglio che il contenuto della mappa rifletta ciò che l'applicazione ha aggiunto alla mappa piuttosto che eseguire una query dinamica.

Ci sono 4 tipi di mappa voglio archiviare

private Map<String, String> map0; 
    private Map<String, Entity> map1; 
    private Map<Entity, String> map2; 
    private Map<Entity, Entity> map3; 

In questi casi non esiste una relazione tra la chiave valore & e né v'è alcuna relazione con la tenuta entità. Devo essere in grado di specificare il nome della tabella di join oltre ai nomi di colonna per il valore chiave &.

Ho provato quanto segue

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

Caso 0 Mappa funziona bene & generato join tabella ha colonne DEPARTMENT, VALORE, CHIAVE

Gli altri tre casi funziona in quanto è possibile memorizzare i dati nelle tabelle & in Java interrogare le tabelle con le relative chiavi/valori & ottenere i risultati attesi, ovvero gestire le entità di memorizzazione utilizzando @ElementCollection

Tuttavia, il nome della colonna sovrascrive utilizzando @Column (name = "valore") & @MapKeyColumn (name = "chiave") vengono ignorati quando la chiave o il valore è un'entità.

Ho provato con @ManyToMany annotazioni come segue

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

Ma ancora una volta il tasto & valore nomi delle colonne le sostituzioni vengono ignorati. Qualcuno sa di un modo per far rispettare queste sovrascritture del nome della colonna.

Grazie in anticipo ...

UPDATE .... Dopo aver esaminato la risposta da @wypieprz credo di sapere l'annotazione corretta per permettere di specificare i nomi delle colonne per il valore & la chiave quando la mappa è codificato da una base con un valore di entità.

utilizzando i seguenti

@ManyToMany(targetEntity = com.demo.bb.impls.Employee.class) 
    @JoinTable(name = "TEST_MAP1", [email protected](name="VALUE")) 
    @MapKeyColumn(name="KEY") 
    private Map<String, Employee> map1; 

Utilizzando l'inverseJoinColumn posso specificare il nome della colonna del valore.

Ma se la chiave è un'entità, non ho trovato un modo per specificare il nome della colonna chiave.Come dice il documento @MapKeyColumn "specifica il mapping per la colonna chiave di una mappa la cui chiave di mappa è un tipo di base"

Non sono sicuro delle annotazioni da utilizzare quando la chiave è un'entità & il valore è un di base. L'utilizzo di ManyToMany non funziona semplicemente & Penso di dover usare ElementCollection ma ancora non riesco a trovare un modo per specificare il nome della colonna chiave.

AGGIORNAMENTO 2 ... Grazie a Peter Halicky per una soluzione.

In sintesi, per nominare tutte e 3 le colonne su ciascuno dei casi è necessario fare qualcosa di simile.

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

Nota due casi sono specificati come ElementCollection ma i due casi in cui il valore sia un altro soggetto bisogno di usare ManyToMany.

+0

'@ ElementCollection' e' @ CollectionTable' deve essere utilizzato solo per i tipi di base e embeddables, per gli enti usano '@ OneToMany' o' @ ManyToMany'. Nota: non è necessario '@ MapKeyClass' e' targetEntity' per il tipo java.util.Map – wypieprz

+0

Sto usando @MapKeyClass perché il java.util.Map digitato è stato digitato utilizzando un'interfaccia per l'entità. È necessario MapKeyClass per indicare quale classe di entità instaniate. – James

+0

Come ho detto nella domanda originale, ho provato a utilizzare @ManyToMany ma non sovrascrive i nomi delle colonne quando la chiave o il valore è un'entità – James

risposta

5

Sto utilizzando un'entità come chiave per una mappa, come di seguito. Usando l'annotazione @MapKeyJoinColumn potrei specificare il nome della colonna che è la chiave della mappa. Questo ha funzionato per me su Hibernate, non so quali altre implementazioni JPA faranno, ma sicuramente vale la pena provare.

@ElementCollection 
@CollectionTable(name="breed_descriptions", joinColumns={ @JoinColumn(name="breed") }) 
@Column(name="description") 
@MapKeyJoinColumn(name="language") 
private Map<Language, String> descriptions = new HashMap<>();