2010-08-13 2 views
7

J'ai créé deux entités JPA (Client, InstrumentTraded) en utilisant Hibernate en tant que fournisseur ayant une relation ManyToMany. Après avoir laissé Hibernate générer les tables pour MySQL, il apparaît que la table de relations ManyToMany ne contient pas de clés primaires pour les deux clés étrangères. Cela permet des enregistrements en double dans la table many-to-many, ce qui n'est pas le résultat souhaité.La relation ManyToMany utilisant JPA avec le fournisseur Hibernate ne crée pas de clés primaires

tables générées:

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

Table préféré:

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

Entités:

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

    ... 

} 

Après avoir fait quelques recherche, il semble que la seule solution est mapping a join table with additional columns en utilisant @OneToMany@IdClass et une classe de clé primaire composite lorsque je n'ai pas besoin de colonnes supplémentaires. Est-ce la seule solution à part celle que j'ai incluse dans le code ci-dessus, qui utilise un @UniqueConstraint avec les deux colonnes de clé étrangère sur le mappage @ManyToMany? Il semble un peu ridicule la quantité de travail nécessaire pour un scénario commun comme celui-ci. Merci!

+0

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

+0

Aussi vaut la peine de vérifier si vous n'avez pas ajouté accidentellement un enregistrement deux fois, cela m'est arrivé, alors 'list.add (x); list.add (x); 'les résultats sont dupliqués dans les listes. – CsBalazsHungary

Répondre

2

Votre mappage semble étrange (en particulier la partie joinColumn de l'annotation @JoinTable). Je me attends quelque chose comme ceci:

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

Mais à moins que vous souhaitez remplacer les valeurs par défaut (et je suppose que vous faites), je voudrais juste sauter le @JoinTable.

+0

Je ne veux pas remplacer les valeurs par défaut, car il pluralise le instrument_traded_id (instruments_traded_id). J'ai une stratégie de nommage personnalisée qui ajoute "_id" si "_id" n'existe pas à la fin d'une clé étrangère. Je peux enlever le joinColumns = @ JoinColumn.Avez-vous un exemple de ManyToMany qui crée une clé primaire composée de deux clés étrangères dans la table ManyToMany? – dukethrash

+0

@dukethrash: 'Avez-vous un exemple de ManyToMany qui crée une clé primaire composée de deux clés étrangères dans la table ManyToMany?' C'est le comportement par défaut si elle est correctement annotée. Avez-vous essayé sans le 'joinColumn' (ou avec le précédent)? –

+0

Oui j'ai essayé le vôtre (à l'exception que referenceColumn est en fait référencéColumnName) et il ne génère toujours pas les clés primaires. J'ai même ajouté ce qui suit sur InstrumentTraded juste pour voir si cela changerait quelque chose. @ManyToMany (fetch = FetchType.LAZY, mappedBy = "instrumentsTraded") private Liste clients; – dukethrash

0

Ou Divisez votre @ManyToMany en @OneToMany - relation @ManyToOne Voir here comment vous pouvez accomplir cette cartographie

6

est ici un moyen de résoudre le problème:

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; 

Ceci est pour le mappage unidirectionnel. Si vous souhaitez une relation bidirectionnelle, modifiez le mappage dans InstrumentTraded.class à la même chose.

15

J'ai eu un problème similaire. Tout ce que je ne faisais que j'ai changé le type de collection de liste pour définir:

private List<InstrumentTraded> instrumentsTraded; 

à

private Set<InstrumentTraded> instrumentsTraded; 

Et en quelque sorte Hibernate génère maintenant des clés primaires pour la table de jointure.

+0

"Toutes les grandes choses sont simples ..." –

+0

Est-ce que c'est? Ou est-ce juste le Java Set qui fait son travail sur la mémoire? – ViniciusPires

+0

Aussi vaut la peine de vérifier si vous n'avez pas accidentellement ajouté deux fois un enregistrement, cela m'est arrivé, donc 'list.add (x); list.add (x); 'les résultats sont dupliqués dans les listes. – CsBalazsHungary

Questions connexes