6 Relaciones de Entidades¶
En Java Persistence API (JPA), las relaciones de entidad son una parte fundamental para modelar las relaciones entre las clases de entidad en tu aplicación y, en última instancia, mapearlas a la base de datos. Las relaciones de entidad permiten definir cómo las entidades se relacionan entre sí y cómo se almacenan y recuperan en la base de datos.
Los tipos de relaciones entre entidades son similares a las relaciones que existen entre entidades en las bases de datos, tenemos relación de uno a uno, relación de uno a muchos, relación de muchos a uno y relación de muchos a muchos.
Cuando se trabaja con relaciones en JPA, una de las entidades involucradas se considera la entidad propietaria de la relación, mientras que la otra se considera la entidad inversa o no propietaria. La entidad propietaria es la que controla cómo se mapea la relación en la base de datos y, por lo general, es la que contiene la clave foránea que establece la relación.
One to one¶
Es una relación uno a uno, es decir una entidad se relaciona con exactamente una entidad en el otro lado de la relación.
Con la anotación @OneToOne
(o su etiqueta equivalente <one-to-one>
) indicamos el atributo de la clase que tiene relación.
El atributo mappedBy
se utiliza en una relación bidireccional entre entidades en JPA para indicar cuál es el campo en la entidad inversa que mapea la relación. Cuando se establece mappedBy, se está definiendo que la entidad actual no es la propietaria de la relación y que la propiedad de la relación se encuentra en la entidad que se especifica en mappedBy.
En el ejemplo, tenemos una relación One-to-One entre las entidades Student y Address. La entidad Student contiene una referencia a la entidad Address, y viceversa, para representar una relación de estudiante a dirección. Aquí, mappedBy
no se utiliza en la entidad Student, lo que indica que Student es el propietario de la relación y es responsable de la clave foránea en la tabla de la base de datos.
En el caso de la entidad Address, mappedBy = "address"
indica que la entidad Address no es la propietaria de la relación. En cambio, la relación se mapea a través del campo address en la entidad Student. Esto significa que la entidad Student es la propietaria de la relación y contiene la clave foránea en la tabla de la base de datos que se utiliza para relacionar un estudiante con una dirección.
La etiqueta <join-column>
se utiliza para personalizar la configuración de la columna de clave foránea en una relación, pero no es necesaria si deseas utilizar la configuración predeterminada.
@Entity
public class Student {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne
@JoinColumn(name = "address_id")
private Address address;
// Getters y setters
}
@Entity
public class Address {
@Id
@GeneratedValue
private Long id;
private String street;
private String city;
@OneToOne(mappedBy = "address")
private Student student;
// Getters y setters
}
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
version="2.2">
<entity class="com.example.model.Student">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="name"/>
<one-to-one name="address">
<join-column name="address_id"/>
</one-to-one>
</attributes>
</entity>
<entity class="com.example.model.Address">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="street"/>
<basic name="city"/>
<one-to-one name="student" mapped-by="address"/>
</attributes>
</entity>
</entity-mappings>
One to many¶
En la relación uno a muchos, un registro de una entidad se relaciona con varios registros de otra entidad.
Con la anotación @OneToMany
(o su etiqueta equivalente <one-to-many>
) indicamos el atributo de la clase que tiene relación de uno a muchos. En la otra entidad (la no propietaria), indicamos la anotación contraria @ManyToOne
(o su equivalente <many-to-one>
)
@Entity
public class Department {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "department")
private List<Employee> employees;
// Getters y setters
}
@Entity
public class Employee {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "department_id") // Nombre de la columna de clave foránea
private Department department;
// Getters y setters
}
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
version="2.2">
<entity class="com.example.model.Department">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="name"/>
<one-to-many name="employees">
<map-key-column name="department_id"/> <!-- Nombre de la columna de clave foránea -->
</one-to-many>
</attributes>
</entity>
<entity class="com.example.model.Employee">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="name"/>
<many-to-one name="department">
<join-column name="department_id"/> <!-- Nombre de la columna de clave foránea -->
</many-to-one>
</attributes>
</entity>
</entity-mappings>
En el ejemplo anterior, Employee es la entidad propietaria de la relación One-to-Many y la entidad Department usa la anotación con el mappedBy
. La entidad Employee contiene una clave foránea llamada department_id que referencia al departamento al que pertenece.
Many to many¶
En la relación muchos a muchos, varios registros de una entidad se relacionan con varios registros de otra entidad.
Con la anotación @ManyToMany
(o su etiqueta equivalente <many-to-many>
) indicamos el atributo de la clase que tiene relación de muchos a muchos.
@Entity
public class Student {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany
@JoinTable(name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id"))
private List<Course> courses;
// Getters y setters
}
@Entity
public class Course {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy = "courses")
private List<Student> students;
// Getters y setters
}
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
version="2.2">
<entity class="com.example.model.Student">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="name"/>
<many-to-many name="courses">
<join-table name="student_course">
<join-column name="student_id"/>
<inverse-join-column name="course_id"/>
</join-table>
</many-to-many>
</attributes>
</entity>
<entity class="com.example.model.Course">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="name"/>
<many-to-many name="students" mapped-by="courses"/>
</attributes>
</entity>
</entity-mappings>
En este ejemplo, tanto Student como Course son propietarios de la relación Many-to-Many. La anotación @ManyToMany
se utiliza en ambas entidades para establecer la relación, y se utiliza @JoinTable
para especificar la tabla de unión (student_course) que asocia las dos entidades. Esta anotación permite especificar el nombre de la tabla intermedia, así como las columnas de clave foránea (join columns) que conectan las tablas de las entidades relacionadas.
Explicación de los atributos de @JoinTable
:
name
: Especifica el nombre de la tabla intermedia que se crea para la relación Many-to-Many. En este caso, la tabla intermedia se llama "student_course".joinColumns
: Especifica las columnas de clave foránea en la tabla intermedia que hacen referencia a la entidad actual (Student). En este caso, la columna de clave foránea en la tabla intermedia "student_course" que se relaciona con la entidad Student se llama "student_id".inverseJoinColumns
: Especifica las columnas de clave foránea en la tabla intermedia que hacen referencia a la entidad relacionada (Course). En este caso, la columna de clave foránea en la tabla intermedia "student_course" que se relaciona con la entidad Course se llama "course_id".
La anotación @JoinTable se utiliza en una de las dos entidades que participan en una relación Many-to-Many para configurar la tabla de unión (tabla intermedia) que conecta las dos entidades. Generalmente, se coloca en la entidad propietaria de la relación o en la entidad que tiene más control sobre la configuración de la tabla de unión.
La otra entidad, aunque aún se considera propietaria de la relación, no necesariamente contendrá @JoinTable
, ya que asumirá la configuración definida en la entidad principal propietaria. En su lugar, la otra entidad puede utilizar mapped-by
para establecer la relación inversa y, por lo tanto, no necesita especificar nuevamente los detalles de la tabla de unión.