comment créer une clé primaire composite (annotation de persistance java)

Comment faire en sorte que la table user_roles définit les deux colonnes (userID, roleID) en tant que clé primaire composite. devrait être facile, mais je ne me souviens plus / pas.

En entité user :

 @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "user_roles") public List getRoles() { return roles; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public Integer getUserID() { return userID; } 

Dans l’entité de roles :

 @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "user_roles") public List getUsers() { return users; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public Integer getRoleID() { return roleID; } 

Je vous remercie.

** PLUS D’INFORMATIONS

Il existe donc une troisième table user_roles (générée automatiquement par ci-dessus) qui prend l’ userID user de user entité user et l’ roleID roles entité roles . Maintenant, j’ai besoin que ces deux colonnes de la table générée ( user_roles ) soient une clé primaire composite.

Vous avez déjà eu quelques bonnes réponses sur la façon de faire exactement ce que vous demandez.

À titre de référence, permettez-moi simplement de mentionner la méthode recommandée dans Hibernate, qui consiste à utiliser une clé de substitution comme clé primaire et à marquer les clés de l’entreprise comme étant NaturalId:

Bien que nous recommandons l’utilisation de clés de substitution en tant que clés primaires, vous devez essayer d’identifier les clés naturelles pour toutes les entités. Une clé naturelle est une propriété ou une combinaison de propriétés unique et non nulle. C’est aussi immuable. Mappez les propriétés de la clé naturelle à l’intérieur de l’élément. Hibernate générera la clé unique nécessaire et les contraintes de nullité et, par conséquent, votre mappage sera plus auto-documenté.

Il est recommandé d’implémenter equals () et hashCode () pour comparer les propriétés de clé naturelle de l’entité.

Dans le code, en utilisant des annotations, ceci ressemblerait à ceci:

 @Entity public class UserRole { @Id @GeneratedValue private long id; @NaturalId private User user; @NaturalId private Role role; } 

Cela vous évitera beaucoup de maux de tête sur la route, car vous découvrirez à quel moment vous devez fréquemment référencer / mapper la clé primaire composée.

J’ai trouvé ça difficile et, à la fin, j’ai juste renoncé à lutter contre Hibernate et j’ai décidé de suivre le courant. Je comprends tout à fait que cela pourrait ne pas être possible dans votre cas, car vous pourriez avoir affaire à des logiciels hérités ou à des dépendances, mais je voulais simplement le mentionner pour référence future. ( Si vous ne pouvez pas l’utiliser, peut-être que quelqu’un d’autre peut le faire !)

Afin de répondre à vos besoins, vous pouvez mapper votre @ManyToMany en tant que mappage @OneToMany. De cette façon, USER_ROLE contiendra USER_ID et ROLE_ID en tant que clé primaire composée.

Je vais vous montrer comment:

 @Entity @Table(name="USER") public class User { @Id @GeneratedValue private Integer id; @OneToMany(cascade=CascadeType.ALL, mappedBy="joinedUserRoleId.user") private List joinedUserRoleList = new ArrayList(); // no-arg required constructor public User() {} public User(Integer id) { this.id = id; } // addRole sets up bidirectional relationship public void addRole(Role role) { // Notice a JoinedUserRole object JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(this, role)); joinedUserRole.setUser(this); joinedUserRole.setRole(role); joinedUserRoleList.add(joinedUserRole); } } @Entity @Table(name="USER_ROLE") public class JoinedUserRole { public JoinedUserRole() {} public JoinedUserRole(JoinedUserRoleId joinedUserRoleId) { this.joinedUserRoleId = joinedUserRoleId; } @ManyToOne @JoinColumn(name="USER_ID", insertable=false, updatable=false) private User user; @ManyToOne @JoinColumn(name="ROLE_ID", insertable=false, updatable=false) private Role role; @EmbeddedId // Implemented as static class - see bellow private JoinedUserRoleId joinedUserRoleId; // required because JoinedUserRole contains composite id @Embeddable public static class JoinedUserRoleId implements Serializable { @ManyToOne @JoinColumn(name="USER_ID") private User user; @ManyToOne @JoinColumn(name="ROLE_ID") private Role role; // required no arg constructor public JoinedUserRoleId() {} public JoinedUserRoleId(User user, Role role) { this.user = user; this.role = role; } public JoinedUserRoleId(Integer userId, Integer roleId) { this(new User(userId), new Role(roleId)); } @Override public boolean equals(Object instance) { if (instance == null) return false; if (!(instance instanceof JoinedUserRoleId)) return false; final JoinedUserRoleId other = (JoinedUserRoleId) instance; if (!(user.getId().equals(other.getUser().getId()))) return false; if (!(role.getId().equals(other.getRole().getId()))) return false; return true; } @Override public int hashCode() { int hash = 7; hash = 47 * hash + (this.user != null ? this.user.hashCode() : 0); hash = 47 * hash + (this.role != null ? this.role.hashCode() : 0); return hash; } } } 

rappelles toi

Si un object a un identifiant atsortingbué ou une clé composite, l’identifiant DEVRAIT ÊTRE ASSIGNÉ à l’instance d’object AVANT d’appeler save ().

Nous avons donc créé un constructeur JoinedUserRoleId comme celui-ci pour en prendre soin.

 public JoinedUserRoleId(User user, Role role) { this.user = user; this.role = role; } 

Et enfin la classe de rôle

 @Entity @Table(name="ROLE") public class Role { @Id @GeneratedValue private Integer id; @OneToMany(cascade=CascadeType.ALL, mappedBy="JoinedUserRoleId.role") private List joinedUserRoleList = new ArrayList(); // no-arg required constructor public Role() {} public Role(Integer id) { this.id = id; } // addUser sets up bidirectional relationship public void addUser(User user) { // Notice a JoinedUserRole object JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(user, this)); joinedUserRole.setUser(user); joinedUserRole.setRole(this); joinedUserRoleList.add(joinedUserRole); } } 

Selon le tester, écrivons ce qui suit

 User user = new User(); Role role = new Role(); // code in order to save a User and a Role Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Serializable userId = session.save(user); Serializable roleId = session.save(role); session.getTransaction().commit(); session.clear(); session.close(); // code in order to set up bidirectional relationship Session anotherSession = HibernateUtil.getSessionFactory().openSession(); anotherSession.beginTransaction(); User savedUser = (User) anotherSession.load(User.class, userId); Role savedRole = (Role) anotherSession.load(Role.class, roleId); // Automatic dirty checking // It will set up bidirectional relationship savedUser.addRole(savedRole); anotherSession.getTransaction().commit(); anotherSession.clear(); anotherSession.close(); 

Avis selon le code ci-dessus AUCUNE RÉFÉRENCE à la classe JoinedUserRole.

Si vous voulez récupérer un JoinedUserRole, essayez ce qui suit.

 Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Integer userId; Integer roleId; // Lets say you have set up both userId and roleId JoinedUserRole joinedUserRole = (JoinedUserRole) session.get(JoinedUserRole.class, new JoinedUserRole.JoinedUserRoleId(userId, roleId)); // some operations session.getTransaction().commit(); session.clear(); session.close(); 

Cordialement,

Les clés composites sont créées à l’aide de @IdClass (l’autre méthode consiste à utiliser @EmbeddedId et @Embeddable, mais vous ne savez pas exactement ce que vous recherchez), la @IdClass est la suivante

 @Entity @IdClass(CategoryPK.class) public class Category { @Id protected Ssortingng name; @Id protected Date createDate; } public class CategoryPK implements Serializable { Ssortingng name; Date createDate; public boolean equals(object other) { //implement a equals that the PP can use to determine //how the CategoryPK object can be identified. } public int hashCode(){ return Super.hashCode(); } } 

ma catégorie ici sera votre user_roles et le nom et createDate seront votre userid et roleid

Merci d’avoir amélioré votre question … et pris en compte les suggestions.

(Désolé, c’est un peu étrange que vous postfixiez vos entités avec Daos, mais ce n’est pas le point.)

Je ne suis pas sûr qu’il rest un problème:

  • Les deux entités que vous décrivez ont chacune une PK, pas une paire de.
  • La table de liens n’a pas d’entité correspondante, elle est définie implicitement par les deux entités et leur relation ManyToMany. Si vous avez besoin d’une troisième entité, remplacez votre ManyToMany par une paire de relations OneToMany et ManyToOne.

J’ai eu le même problème avec les clés primaires. Je connaissais également la solution avec les classes @Embeddable et @EmbeddedId. Mais je voulais juste la solution simple avec les annotations.

Eh bien j’ai trouvé l’illumination à travers cet article: http://www.vaannila.com/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html

et voici la magie:

Cela génère une clé primaire sur la table de jointure:

 @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name="classA_classB") private Set classesA; 

cela ne génère pas de clé primaire sur la table de jointure:

 @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name="classA_classB") private List classesA; 

au moins dans mon environnement

Notez que la différence utilise Set ou List.