2

J'ai une situation qui est assez similaire à celle décrite dans le diagramme de cette question: JPA. JoinTable and two JoinColumns, mais avec des problèmes différents.JPA @JoinTable - Trois colonnes d'ID

J'ai trois tables: Function, Group et Location. Actuellement, j'ai une table de jointure mise en place entre Location et Group en utilisant @JoinTable. Il est @ManyToMany des deux côtés, et fonctionne parfaitement bien.

Je tente d'ajouter la contrainte qu'aucun Location ne doit être associé à plus d'un Group qui a le même Function. J'ai donc ajouté une colonne pour Function à ma table de jointure dans mon schéma SQL et une contrainte d'unicité dans les colonnes Location et Function, comme ceci:

create table function_table (
    id varchar(50), 
    primary key(id) 
); 

create table group_table (
    id varchar(50), 
    function_id varchar(50) not null, 
    primary key(id) 
); 

alter table group_table add constraint FK_TO_FUNCTION foreign key (function_id) references function_table; 

create table location_table (
    id varchar(50), 
    primary key(id) 
); 

create table group_location_join (
    location_id varchar(50) not null, 
    group_id varchar(50) not null, 
    function_id varchar(50) not null, 
    primary key(location_id, group_id, function_id), 
    unique(location_id, function_id) 
); 

alter table group_location_join add constraint FK_TO_LOCATION foreign key (location_id) references location_table; 
alter table group_location_join add constraint FK_TO_GROUP foreign key (group_id) references group_table; 
alter table group_location_join add constraint FK_TO_FUNCTION foreign key (function_id) references function_table; 

Je puis essayé de mettre en place ce qui suit dans mes entités du modèle:

@Entity 
@Table(name = "function_table") 
public class Function { 
    @Id 
    @Column(name = "id", length = 50) 
    private String id; 
} 

@Entity 
@Table(name = "group_table") 
public class Group { 
    @Id 
    @Column(name = "id", length = 50) 
    private String id; 

    @ManyToOne 
    @JoinColumn(name = "function_id", referencedColumnName = "id", nullable = false) 
    private Function function; 

    @ManyToMany 
    @JoinTable(name = "group_location_join", 
    joinColumns = {@JoinColumn(name = "group_id", referencedColumnName = "id"), 
        @JoinColumn(name = "function_id", referencedColumnName = "function_id")}, 
    inverseJoinColumns = @JoinColumn(name="location_id", referencedColumnName = "id")) 
    private Set<Location> locations; 
} 

@Entity 
@Table(name = "location_table") 
public class Location { 
    @Id 
    @Column(name = "id", length = 50) 
    private String id; 

    @ManyToMany 
    @JoinTable(name = "group_location_join", 
    joinColumns = @JoinColumn(name="location_id", referencedColumnName = "id") 
    inverseJoinColumns = {@JoinColumn(name = "group_id", referencedColumnName = "id"), 
        @JoinColumn(name = "function_id", referencedColumnName = "function_id")}) 
    private Set<Group> groups; 
} 

(de toute évidence, il est plus à ces entités, mais je les Bx_boom que les parties concernées à cette question.)

cela ne fonctionne pas. Quand j'écris un test simple pour créer un Location associé à un Group qui est associée à une Function, la minute où je tente de vider la session pour valider la transaction, Hibernate me donne ceci:

java.lang.ClassCastException: my.package.Group cannot be cast to java.io.Serializable 

Je pense que ce qui se passe Hibernate est confus, lève les mains et dit: "Je vais juste le sérialiser, l'envoyer à la base de données, et j'espère qu'il sait ce qui se passe."

Quand j'ajoute implements Serializable et ajouter un serialVersionUID à Group, je puis obtenir ceci:

org.hibernate.exception.SQLGrammarException: user lacks privilege or object not found: FUNCTION_ID 

Je ne suis pas sûr de savoir comment procéder à ce point, ou si peut-être je l'ai déjà trop avancé vers le bas le mauvais chemin. Peut-être que je ne pense pas au SQL correctement, et il y a un moyen beaucoup plus facile d'assurer cette contrainte qui n'implique pas tout ce ridicule.

Éditer: Dans mon système, les DAO pour les tables impliquées n'ont aucune capacité de sauvegarde. Ce qui signifie que tant que ma contrainte est configurée dans la base de données, mon application ne s'en soucie pas; il ne peut pas insérer des choses qui violent la contrainte parce qu'il ne peut pas insérer des choses du tout.

Edit 2: Je ne l'origine résolu le problème posé, et au lieu simplement ajouté une troisième colonne dans mon schéma de base de données sans toucher le code Java, comme indiqué dans mon premier Modifier section ci-dessus. Mais depuis j'ai expérimenté avec la création d'un objet table de jointure explicite avec une clé composée @Embedded, et cela semble fonctionner.

Répondre

1

Vous essayez de créer une clé primaire composite. Dans Hibernate, vous pouvez le faire en utilisant l'annotation @Embeddable. Dans l'exemple ci-dessous, vous pouvez trouver le moyen d'utiliser une clé composite pour deux entités.

Je crois que vous pouvez aller de l'avant avec cet exemple et créer votre propre version de la clé primaire.

Mapping ManyToMany with composite Primary key and Annotation:

+0

Voulez-vous dire une clé composite 'Group'? Parce que je ne le veux absolument pas. Lorsque quelque chose d'autre dans le système fait référence 'Group' par clé primaire, il ne devrait traiter que de la colonne' id'. Si je donne à 'Group' une clé primaire composite, cela changera ce fait; tout ira chercher 'Group's par' id' ET 'function_id'. Je ne veux pas ça. Je veux seulement obtenir 'function_id' dans la table' group_location_join'. –