¿Cuál es la diferencia entre las asociaciones unidireccionales y bidireccionales?
Dado que la tabla generada en la base de datos es la misma, la única diferencia que encontré es que cada lado de las asociaciones bidireccionales tendrá una referencia al otro, y el unidireccional no.
Esta es una asociación unidireccional
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
}
La asociación bidireccional
public class User {
private int id;
private String name;
@ManyToOne
@JoinColumn(
name = "groupId")
private Group group;
}
public class Group {
private int id;
private String name;
@OneToMany(mappedBy="group")
private List<User> users;
}
La diferencia es si el grupo tiene una referencia del usuario.
¿Entonces me pregunto si esta es la única diferencia? cual se recomienda
Respuestas:
La diferencia principal es que la relación bidireccional proporciona acceso de navegación en ambas direcciones, para que pueda acceder al otro lado sin consultas explícitas. También le permite aplicar opciones en cascada a ambas direcciones.
Tenga en cuenta que el acceso a la navegación no siempre es bueno, especialmente para las relaciones "uno a muchos" y "muchos a muchos". Imagine un
Group
que contiene miles deUser
s:¿Cómo accederías a ellos? Con tantos correos
User
electrónicos, por lo general, debe aplicar algo de filtrado y / o paginación, de modo que debe ejecutar una consulta de todos modos (a menos que use el filtrado de recopilación , que para mí parece un truco). Algunos desarrolladores pueden tender a aplicar filtros en la memoria en tales casos, lo que obviamente no es bueno para el rendimiento. Tenga en cuenta que tener una relación de este tipo puede alentar a este tipo de desarrolladores a usarla sin tener en cuenta las implicaciones de rendimiento.¿Cómo agregarías nuevos correos
User
electrónicos alGroup
? Afortunadamente, Hibernate observa el lado propietario de la relación cuando la persiste, por lo que solo puede establecerlaUser.group
. Sin embargo, si desea mantener los objetos en la memoria constante, también es necesario añadirUser
aGroup.users
. ¡Pero haría que Hibernate obtenga todos los elementos deGroup.users
la base de datos!Por lo tanto, no puedo estar de acuerdo con la recomendación de las mejores prácticas . Debe diseñar relaciones bidireccionales con cuidado, considerando los casos de uso (¿necesita acceso de navegación en ambas direcciones?) Y las posibles implicaciones de rendimiento.
Ver también:
fuente
setGroup()
desdeaddUser()
el fin de mantener ambos lados consistente.setGroup()
sinaddUser()
, pero daría como resultado un estado inconsistente de los objetos en la memoria.Hay dos diferencias principales.
Accediendo a los lados de la asociación
El primero está relacionado con cómo accederá a la relación. Para una asociación unidireccional, puede navegar por la asociación solo desde un extremo.
Entonces, para una
@ManyToOne
asociación unidireccional , significa que solo puede acceder a la relación desde el lado secundario donde reside la clave externa.Si tiene una
@OneToMany
asociación unidireccional , significa que solo puede acceder a la relación desde el lado primario donde reside la clave externa.Para la
@OneToMany
asociación bidireccional , puede navegar por la asociación en ambos sentidos, ya sea desde el lado primario o secundario.También debe usar métodos de utilidad de agregar / quitar para asociaciones bidireccionales para asegurarse de que ambos lados estén sincronizados correctamente .
Actuación
El segundo aspecto está relacionado con el rendimiento.
@OneToMany
, asociaciones unidireccionales no funcionan tan bien como los bidireccionales .@OneToOne
, una asociación bidireccional hará que el padre se busque ansiosamente si Hibernate no puede determinar si se debe asignar el Proxy o un valor nulo .@ManyToMany
, el tipo de colección hace una gran diferencia ya queSets
funciona mejor queLists
.fuente
En términos de codificación, una relación bidireccional es más compleja de implementar porque la aplicación es responsable de mantener ambas partes sincronizadas de acuerdo con la especificación 5 de JPA (en la página 42). Desafortunadamente, el ejemplo dado en la especificación no da más detalles, por lo que no da una idea del nivel de complejidad.
Cuando no se utiliza un caché de segundo nivel, generalmente no es un problema no tener los métodos de relación implementados correctamente porque las instancias se descartan al final de la transacción.
Cuando se usa caché de segundo nivel, si algo se corrompe debido a métodos de manejo de relaciones implementados incorrectamente, esto significa que otras transacciones también verán los elementos corruptos (el caché de segundo nivel es global).
Una relación bidireccional implementada correctamente puede hacer que las consultas y el código sean más simples, pero no debe usarse si realmente no tiene sentido en términos de lógica empresarial.
fuente
No estoy 100% seguro de que esta sea la única diferencia, pero es la principal diferencia. También se recomienda tener asociaciones bidireccionales por los documentos de Hibernate:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html
Específicamente:
Personalmente, tengo un pequeño problema con esta recomendación general: me parece que hay casos en los que un niño no tiene ninguna razón práctica para saber acerca de su padre (por ejemplo, ¿por qué un artículo de pedido necesita saber sobre el pedido? asociado con?), pero también veo valor en él una parte razonable del tiempo. Y dado que la bidireccionalidad realmente no hace daño a nada, no me parece demasiado objetable cumplirla.
fuente