2010-08-13 12 views
7

Ho creato due entità JPA (Client, InstrumentTraded) utilizzando Hibernate come provider con una relazione ManyToMany. Dopo aver lasciato che Hibernate generi le tabelle per MySQL, sembra che la tabella delle relazioni ManyToMany non contenga chiavi primarie per le due chiavi esterne. Ciò consente di duplicare i record nella tabella many-to-many, che non è il risultato desiderato.ManyToMany relationship using JPA with Hibernate provider non crea chiavi primarie

tabelle generate:

client(id,name) 
instrument_traded(id,name) 
client_instrument_traded(FK client_id, FK instrument_traded_id) 

tavolo preferita:

client_instrument_traded(PK,FK client_id, PK,FK instrument_traded_id) 

Entità:

@Entity 
public class Client extends AbstractEntity<Integer> { 

    private static final long serialVersionUID = 1L; 

    @Basic(optional = false) 
    @Column(nullable = false, length = 125) 
    private String name; 

    @ManyToMany(fetch = FetchType.LAZY) 
    @JoinTable(joinColumns = { 
     @JoinColumn}, inverseJoinColumns = { 
     @JoinColumn(name = "instrument_traded_id")}, uniqueConstraints = 
    @UniqueConstraint(name = "UK_client_instruments_traded_client_id_instrument_traded_id", 
    columnNames = {"client_id", "instrument_traded_id"})) 
    @ForeignKey(name = "FK_client_instruments_traded_client_id", 
    inverseName = "FK_client_instruments_traded_instrument_traded_id") 
    private List<InstrumentTraded> instrumentsTraded; 

    public Client() { 
    } 

    public List<InstrumentTraded> getInstrumentsTraded() { 
     return instrumentsTraded; 
    } 

    public void setInstrumentsTraded(List<InstrumentTraded> instrumentsTraded) { 
     this.instrumentsTraded = instrumentsTraded; 
    } 

    ... 
} 



@Entity 
@Table(uniqueConstraints = { 
    @UniqueConstraint(name = "UK_instrument_traded_name", columnNames = {"name"})}) 
public class InstrumentTraded extends AbstractEntity<Integer> { 

    private static final long serialVersionUID = 1L; 

    @Basic(optional = false) 
    @Column(nullable = false, length = 50) 
    private String name; 

    @ManyToMany(mappedBy = "instrumentsTraded", fetch = FetchType.LAZY) 
    private List<Client> clients; 

    public InstrumentTraded() { 
    } 

    public List<Client> getClients() { 
     return clients; 
    } 

    public void setClients(List<Client> clients) { 
     this.clients = clients; 
    } 

    ... 

} 

Dopo aver fatto alcune ricerca sembra l'unica soluzione è per mapping a join table with additional columns utilizzando @OneToMany@IdClass e una classe di chiave primaria composita quando non ho bisogno di colonne aggiuntive. È questa l'unica soluzione oltre a quella che ho incluso nel codice sopra, che utilizza un @UniqueConstraint con le due colonne chiave esterna nella mappatura @ManyToMany? Sembra un po 'ridicola la quantità di lavoro necessaria per uno scenario comune come questo. Grazie!

+0

http://stackoverflow.com/questions/1212058/how-to-make-a-composite-primary-key-java-persistence-annotation/6344626#6344626 – steveeen

+0

Vale anche la pena di verificare se non è stato accidentalmente aggiunto un record due volte, questo è successo a me, quindi 'list.add (x); list.add (x); 'risultati duplicati negli elenchi. – CsBalazsHungary

risposta

2

La mappatura è strana (in particolare la parte joinColumn dell'annotazione @JoinTable). Mi sarei aspettato qualcosa di simile:

@ManyToMany(fetch = FetchType.LAZY) 
@JoinTable(
    joinColumns= 
     @JoinColumn(name="CLIENT_ID", referencedColumnName="ID"), 
    inverseJoinColumns= 
     @JoinColumn(name="instrument_traded_id", referencedColumnName="ID"), 
    uniqueConstraints= 
     @UniqueConstraint(
      name="UK_client_instruments_traded_client_id_instrument_traded_id", 
      columnNames = {"client_id", "instrument_traded_id"} 
     ) 
) 
@ForeignKey(name = "FK_client_instruments_traded_client_id", 
inverseName = "FK_client_instruments_traded_instrument_traded_id") 
private List<InstrumentTraded> instrumentsTraded; 

Ma a meno che non si desidera sovrascrivere le impostazioni di default (e immagino che fate), vorrei solo saltare la @JoinTable.

+0

Desidero sovrascrivere i valori predefiniti perché pluralizza lo instrument_traded_id (instruments_traded_id). Ho una strategia di denominazione personalizzata che aggiunge "_id" se "_id" non esiste alla fine di una chiave esterna. Posso rimuovere joinColumns = @ JoinColumn.Avete un esempio funzionante di ManyToMany che crea una chiave primaria composta da due chiavi esterne nella tabella ManyToMany? – dukethrash

+0

@dukethrash: 'Avete un esempio funzionante di ManyToMany che crea una chiave primaria composta da due chiavi esterne nella tabella ManyToMany?' Questo è il comportamento predefinito se annotato correttamente. Hai provato senza 'joinColumn' (o con quello precedente)? –

+0

Sì, l'ho provato (ad eccezione del fatto che referencedColumn è effettivamente referencedColumnName) e non sta ancora generando le chiavi primarie. Ho persino aggiunto quanto segue su InstrumentTraded solo per vedere se questo cambierebbe qualcosa. @ManyToMany (fetch = FetchType.LAZY, mappedBy = "instrumentsTraded") elenco privato clienti; – dukethrash

0

O Dividere il @ManyToMany in @OneToMany - rapporto @ManyToOne Vedi here come è possibile eseguire questa mappatura

6

Ecco un modo per risolvere il problema:

Client.java:

@ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL) 
@JoinTable(
     joinColumns = {@JoinColumn(name = "client_id")}, 
     inverseJoinColumns = {@JoinColumn(name = "instrument_traded_id")}, 
     uniqueConstraints = {@UniqueConstraint(
      columnNames = {"client_id", "instrument_traded_id"})} 
) 
private List<InstrumentTraded> instrumentsTraded; 

Questo è per la mappatura unidirezionale. Se si desidera una relazione bidirezionale, modificare il mapping in InstrumentTraded.class allo stesso.

15

Ho avuto un problema simile. Tutto quello che ho fatto è stato che ho cambiato il tipo di raccolta da Lista per impostare:

private List<InstrumentTraded> instrumentsTraded; 

a

private Set<InstrumentTraded> instrumentsTraded; 

E in qualche modo Hibernate ora genera chiavi primarie per la tabella unirsi.

+0

"Tutte le grandi cose sono semplici ..." –

+0

Lo fa? O è solo il Java Set che fa il suo lavoro sulla memoria? – ViniciusPires

+0

Vale anche la pena di verificare se accidentalmente non è stato aggiunto un record due volte, questo è successo a me, quindi 'list.add (x); list.add (x); 'risultati duplicati negli elenchi. – CsBalazsHungary

Problemi correlati