Recherche…


Introduction

Un mappage ManyToMany décrit une relation entre des entités où les deux peuvent être associées à plusieurs instances l'une de l'autre et est définie par l'annotation @ManyToMany .

Contrairement à @OneToMany où une colonne de clé étrangère dans la table de l'entité peut être utilisée, ManyToMany nécessite une table de jointure, qui mappe les entités entre elles.

Paramètres

Annotation Objectif
@TableGenerator Définit un générateur de clé primaire pouvant être référencé par nom lorsqu'un élément generator est spécifié pour l'annotation GeneratedValue
@GeneratedValue Fournit la spécification de stratégies de génération pour les valeurs des clés primaires. Il peut être appliqué à une propriété de clé primaire ou à un champ d'une entité ou à une super-classe mappée conjointement avec l'annotation Id.
@ManyToMany Spécifie la relation entre les entités Employé et Projet, de sorte que de nombreux employés puissent travailler sur plusieurs projets.
mappedBy="projects" Définit une relation bidirectionnelle entre Employee et Project
@JoinColumn Spécifie le nom de la colonne qui fera référence à l'entité à considérer comme propriétaire de l'association
@JoinTable Spécifie la table dans la base de données qui tiendra l'employé à projeter des relations à l'aide de clés étrangères

Remarques

  • @TableGenerator et @GeneratedValue sont utilisés pour la création automatique d'ID à l'aide du générateur de table jpa.
  • L'annotation @ManyToMany spécifie la relation entre les entités Employé et Projet.
  • @JoinTable spécifie le nom de la table à utiliser en tant que table de jointure jpa à plusieurs mappages entre Employee et Project en utilisant name = “employee_project”. Cela est fait car il n'existe aucun moyen de déterminer la propriété d'un mappage jpa plusieurs à plusieurs, car les tables de base de données ne contiennent pas de clés étrangères pour faire référence à une autre table.
  • @JoinColumn spécifie le nom de la colonne qui fera référence à l'entité à considérer en tant que propriétaire de l'association, tandis que @inverseJoinColumn spécifie le nom du côté inverse de la relation. (Vous pouvez choisir n'importe quel côté pour être considéré comme propriétaire. Assurez-vous juste que ces côtés en relation). Dans notre cas, nous avons choisi Employee comme propriétaire, de sorte que @JoinColumn se réfère à la colonne idemployee dans la table de jointure employee_project et que @InverseJoinColumn fait référence à idproject qui est inversé par rapport au mappage plusieurs à plusieurs.
  • L'annotation @ManyToMany dans l'entité de projet montre une relation inverse et utilise donc mappedBy = projects pour faire référence au champ dans l'entité Employee.

L'exemple complet peut être référencé ici

Employé à projeter de nombreuses cartes à plusieurs

Entité employé.

package com.thejavageek.jpa.entities;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.TableGenerator;

@Entity
public class Employee {

    @TableGenerator(name = "employee_gen", table = "id_gen", pkColumnName = "gen_name", valueColumnName = "gen_val", allocationSize = 100)
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "employee_gen")
    private int idemployee;
    private String name;

    @ManyToMany(cascade = CascadeType.PERSIST)
    @JoinTable(name = "employee_project", joinColumns = @JoinColumn(name = "idemployee"), inverseJoinColumns = @JoinColumn(name = "idproject"))
    private List<Project> projects;

    public int getIdemployee() {
        return idemployee;
    }

    public void setIdemployee(int idemployee) {
        this.idemployee = idemployee;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Project> getProjects() {
        return projects;
    }

    public void setProjects(List<Project> projects) {
        this.projects = projects;
    }

}

Entité de projet:

package com.thejavageek.jpa.entities;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.TableGenerator;

@Entity
public class Project {

    @TableGenerator(name = "project_gen", allocationSize = 1, pkColumnName = "gen_name", valueColumnName = "gen_val", table = "id_gen")
    @Id
    @GeneratedValue(generator = "project_gen", strategy = GenerationType.TABLE)
    private int idproject;
    private String name;

    @ManyToMany(mappedBy = "projects", cascade = CascadeType.PERSIST)
    private List<Employee> employees;

    public int getIdproject() {
        return idproject;
    }

    public void setIdproject(int idproject) {
        this.idproject = idproject;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }

}

Code de test

/ * Créer EntityManagerFactory * / EntityManagerFactory emf = Persistence .createEntityManagerFactory ("JPAExamples");

    /* Create EntityManager */
    EntityManager em = emf.createEntityManager();

    EntityTransaction transaction = em.getTransaction();

    transaction.begin();

    Employee prasad = new Employee();
    prasad.setName("prasad kharkar");

    Employee harish = new Employee();
    harish.setName("Harish taware");

    Project ceg = new Project();
    ceg.setName("CEG");

    Project gtt = new Project();
    gtt.setName("GTT");

    List<Project> projects = new ArrayList<Project>();
    projects.add(ceg);
    projects.add(gtt);

    List<Employee> employees = new ArrayList<Employee>();
    employees.add(prasad);
    employees.add(harish);

    ceg.setEmployees(employees);
    gtt.setEmployees(employees);

    prasad.setProjects(projects);
    harish.setProjects(projects);

    em.persist(prasad);

    transaction.commit();

Comment gérer la clé composée sans annotation intégrable

Si tu as

Role:
+-----------------------------+
| roleId | name | discription |
+-----------------------------+


Rights:
+-----------------------------+
| rightId | name | discription|
+-----------------------------+

rightrole
+------------------+
| roleId | rightId | 
+------------------+

Dans le scénario ci-dessus, la table de rightrole a une clé composée et pour y accéder dans l'utilisateur JPA, il faut créer une entité avec une annotation Embeddable .

Comme ça:

Entité pour la table de la droite est:

    @Entity
    @Table(name = "rightrole")
    public class RightRole extends BaseEntity<RightRolePK> {
    
        private static final long serialVersionUID = 1L;
    
        @EmbeddedId
        protected RightRolePK rightRolePK;

    
        @JoinColumn(name = "roleID", referencedColumnName = "roleID", insertable = false, updatable = false)
        @ManyToOne(fetch = FetchType.LAZY)
        private Role role;
    
        @JoinColumn(name = "rightID", referencedColumnName = "rightID", insertable = false, updatable = false)
        @ManyToOne(fetch = FetchType.LAZY)
        private Right right;

        ......
     }


    @Embeddable
    public class RightRolePK implements Serializable {
    private static final long serialVersionUID = 1L;

      @Basic(optional = false)
      @NotNull
      @Column(nullable = false)
      private long roleID;

      @Basic(optional = false)
      @NotNull
      @Column(nullable = false)
     private long rightID;

   .....

}

L'annotation intégrable convient à un seul objet, mais cela pose problème lors de l'insertion d'enregistrements en masse.

Le problème est à chaque fois que l' utilisateur veut créer un nouveau role avec les rights alors premier utilisateur doivent store(persist) role objet et l' utilisateur doit faire flush pour obtenir nouvellement généré id pour le rôle. Ensuite, l'utilisateur peut le placer dans l'objet de l'entité de rightrole .

Pour résoudre cet utilisateur peut écrire entité de manière légèrement différente.

L'entité pour la table de rôles est:

@Entity
@Table(name = "role")
public class Role {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @NotNull
    @Column(nullable = false)
    private Long roleID;

    
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "role", fetch = FetchType.LAZY)
    private List<RightRole> rightRoleList;
 
    @ManyToMany(cascade = {CascadeType.PERSIST})
    @JoinTable(name = "rightrole",
            joinColumns = {
                @JoinColumn(name = "roleID", referencedColumnName = "ROLE_ID")},
            inverseJoinColumns = {
                @JoinColumn(name = "rightID", referencedColumnName = "RIGHT_ID")})
    private List<Right> rightList;
.......
}

L'annotation @JoinTable se chargera d'insérer dans la table de rightrole même sans entité (tant que cette table n'a que les colonnes id de rôle et de droite).

L'utilisateur peut alors simplement:

Role role = new  Role();
List<Right> rightList = new ArrayList<>();
Right right1 = new Right();
Right right2 = new Right();
rightList.add(right1);
rightList.add(right2);
role.setRightList(rightList);

Vous devez écrire @ManyToMany (cascade = {CascadeType.PERSIST}) dans inverseJoinColumns, sinon vos données parentes seront supprimées si l'enfant est supprimé.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow