jpa
Muchos a muchos mapeos
Buscar..
Introducción
Un mapeo ManyToMany describe una relación entre entidades donde ambas pueden estar relacionadas con más de una instancia de la otra y se define mediante la anotación @ManyToMany .
A diferencia de @OneToMany donde se puede @OneToMany una columna de clave externa en la tabla de la entidad, ManyToMany requiere una tabla de unión, que asigna las entidades entre sí.
Parámetros
| Anotación | Propósito |
|---|---|
@TableGenerator | Define un generador de clave principal al que se puede hacer referencia por nombre cuando se especifica un elemento generador para la anotación GeneratedValue |
@GeneratedValue | Proporciona la especificación de estrategias de generación para los valores de las claves primarias. Puede aplicarse a una propiedad o campo de clave principal de una entidad o una superclase asignada junto con la anotación de Id. |
@ManyToMany | Especifica la relación entre el empleado y las entidades del proyecto, de modo que muchos empleados puedan trabajar en múltiples proyectos. |
mappedBy="projects" | Define una relación bidireccional entre empleado y proyecto. |
@JoinColumn | Especifica el nombre de la columna que se referirá a la Entidad para ser considerado como propietario de la asociación |
@JoinTable | Especifica la tabla en la base de datos que mantendrá a los empleados para proyectar relaciones usando claves externas |
Observaciones
- @TableGenerator y @GeneratedValue se utilizan para la creación automática de ID utilizando el generador de tablas jpa.
- La anotación @ManyToMany especifica la relación entre las entidades Empleado y Proyecto.
- @JoinTable especifica el nombre de la tabla para usar como unir la tabla jpa muchos a muchos mapeo entre el empleado y el proyecto usando name = "employee_project". Esto se hace porque no hay manera de determinar la propiedad de un jpa muchos a muchos mapeos, ya que las tablas de la base de datos no contienen claves externas para hacer referencia a otra tabla.
- @JoinColumn especifica el nombre de la columna que se referirá a la Entidad para que se considere como propietario de la asociación, mientras que @inverseJoinColumn especifica el nombre del lado inverso de la relación. (Puedes elegir cualquier lado para ser considerado como propietario. Solo asegúrate de que esos lados en la relación). En nuestro caso, hemos elegido Empleado como propietario, por lo que @JoinColumn se refiere a la columna idemployee en join table employee_project y @InverseJoinColumn se refiere a idproject que es el lado inverso de jpa muchos a muchos mapeos.
- La anotación @ManyToMany en la entidad del proyecto muestra una relación inversa, por lo tanto, utiliza los proyectos mappedBy = para referirse al campo en la entidad del empleado.
El ejemplo completo puede ser referido aquí
Empleado para proyectar muchos a muchos mapeo
Entidad empleada.
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;
}
}
Entidad del proyecto:
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;
}
}
Código de prueba
/ * Crear 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();
Cómo manejar claves compuestas sin anotación incrustable
Si usted tiene
Role:
+-----------------------------+
| roleId | name | discription |
+-----------------------------+
Rights:
+-----------------------------+
| rightId | name | discription|
+-----------------------------+
rightrole
+------------------+
| roleId | rightId |
+------------------+
En el escenario rightrole tabla de rightrole tiene una clave compuesta y, para acceder a ella, el usuario de JPA debe crear una entidad con anotación Embeddable .
Me gusta esto:
Entidad para la mesa de control es:
@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;
.....
}
La anotación incorporable está bien para un solo objeto, pero dará un problema al insertar registros masivos.
El problema es que cada vez que el usuario desea crear una nueva role con rights , el primer usuario debe store(persist) objeto de la role y luego el usuario debe flush para obtener la id recién generada para la función. entonces y luego el usuario puede ponerlo en el objeto de la entidad de rightrole de la rightrole
Para resolver este usuario puede escribir entidad de forma ligeramente diferente.
La entidad para la tabla de roles es:
@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;
.......
}
La anotación @JoinTable se encargará de insertar en la tabla de rightrole incluso sin una entidad (siempre que esa tabla tenga solo las columnas de ID de rol y derecha).
El usuario puede entonces simplemente:
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);
Debe escribir @ManyToMany (cascade = {CascadeType.PERSIST}) en inverseJoinColumns, de lo contrario, sus datos principales se eliminarán si se elimina el elemento secundario.