Question

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

Dans l'entité utilisateur :

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles")
public List<RoleDAO> getRoles() {
    return roles;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getUserID() {
    return userID;
}

Dans l'entité rôles :

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles")
public List<UserDAO> getUsers() {
    return users;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getRoleID() {
    return roleID;
}

Merci.

** PLUS D'INFO

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

Était-ce utile?

La solution

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

Pour référence, permettez-moi de mentionner la méthode recommandée dans Hibernate, qui consiste à utiliser une clé de substitution en tant que clé primaire et à marquer les clés commerciales en tant que NaturalId:

  

Bien que nous recommandons l'utilisation de   clés de substitution en tant que clés primaires, vous   devrait essayer d'identifier les clés naturelles   pour toutes les entités. Une clé naturelle est un   propriété ou combinaison de propriétés   c'est unique et non nul. Il est   aussi immuable. Cartographier les propriétés de   la clé naturelle à l'intérieur du    élément. Hibernate sera   générer la clé unique nécessaire et   la nullité et, en tant que   résultat, votre cartographie sera plus   auto-documenté.

     

Il est recommandé de mettre en œuvre   equals () et hashCode () pour comparer les   propriétés de clé naturelle de l'entité.

Dans le code, en utilisant des annotations, cela 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, car vous découvrirez quand vous devez fréquemment référencer / mapper la clé primaire composée.

J'ai découvert cela à la dure et à la fin, j'ai simplement abandonné le combat 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 à un logiciel hérité 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 !)

Autres conseils

Pour répondre à vos besoins, vous pouvez mapper votre @ManyToMany en tant que mappage @OneToMany. Ainsi, 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<JoinedUserRole> joinedUserRoleList = new ArrayList<JoinedUserRole>();

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

    }

}

rappelez-vous

  

Si un objet a une assignation   identifiant, ou une clé composite, le   identifiant DEVRAIT ÊTRE ATTRIBUÉ à la   instance d'objet 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<JoinedUserRole> joinedUserRoleList = new ArrayList<JoinedUserRole>();

    // 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 test, é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 NO REFERENCE to JoinedUserRole class.

Si vous souhaitez récupérer un rôle 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();

salutations

Les clés composites sont créées à l'aide de @IdClass (l'autre méthode consiste à utiliser @EmbeddedId et @Embeddable sans savoir lequel vous cherchez), la @IdClass est la suivante

@Entity
@IdClass(CategoryPK.class)
public class Category {
    @Id
    protected String name;

    @Id
    protected Date createDate;

}

public class CategoryPK implements Serializable {

    String 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 sera ici vos rôles utilisateur et le nom et createDate seront votre nom d'utilisateur et votre identifiant de rôle

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

(Désolé, il est un peu étrange que vous postfixiez vos entités avec Daos, mais ce n'est pas la raison.)

Je ne suis pas sûr qu'il reste un problème:

  • Les deux entités que vous décrivez ont chacune une PK et non une paire.
  • 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 dans cet article: http: // www .vaannila.com / hibernate / hibernate-example / hibernate-mapping-many-to-many-using-annotations-1.html

et voici la magie:

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

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="classA_classB")
private Set<ClassA> 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<ClassA> classesA;

au moins dans mon environnement

Notez que la différence consiste à utiliser Définir ou Liste

.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top