Quelle est la différence entre les associations unidirectionnelles et bidirectionnelles?
Étant donné que les tables générées dans la base de données sont toutes identiques, la seule différence que j'ai trouvée est que chaque côté des associations bidirectionnelles aura un renvoi à l'autre, et non unidirectionnel.
Ceci est une association unidirectionnelle
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;
}
L'association bidirectionnelle
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 différence est de savoir si le groupe contient une référence de l'utilisateur.
Alors je me demande si c'est la seule différence? qui est recommandé?
Réponses:
La principale différence est que la relation bidirectionnelle fournit un accès de navigation dans les deux sens, de sorte que vous pouvez accéder à l'autre côté sans requêtes explicites. En outre, il vous permet d'appliquer des options en cascade dans les deux sens.
Notez que l'accès à la navigation n'est pas toujours bon, en particulier pour les relations «un-à-très-plusieurs» et «plusieurs-à-très-plusieurs». Imaginez un
Group
contenant des milliers deUser
s:Comment y accéderiez-vous? Avec autant de
User
s, vous devez généralement appliquer un filtrage et / ou une pagination, de sorte que vous devez quand même exécuter une requête (à moins que vous n'utilisiez le filtrage de collection , ce qui ressemble à un hack pour moi). Certains développeurs ont tendance à appliquer un filtrage en mémoire dans de tels cas, ce qui n'est évidemment pas bon pour les performances. Notez qu'une telle relation peut encourager ce type de développeurs à l'utiliser sans tenir compte des implications en termes de performances.Comment ajouteriez-vous de nouveaux
User
s auGroup
? Heureusement, Hibernate examine le côté propriétaire de la relation lors de sa persistance, vous ne pouvez donc que définirUser.group
. Toutefois, si vous souhaitez que les objets en mémoire restent cohérents, vous devez également ajouterUser
àGroup.users
. Mais cela obligerait Hibernate à récupérer tous les éléments deGroup.users
la base de données!Donc, je ne peux pas être d'accord avec la recommandation des meilleures pratiques . Vous devez concevoir des relations bidirectionnelles avec soin, en tenant compte des cas d'utilisation (avez-vous besoin d'un accès de navigation dans les deux sens?) Et des implications possibles sur les performances.
Voir également:
la source
setGroup()
depuisaddUser()
pour que les deux côtés restent cohérents.setGroup()
sansaddUser()
, mais cela entraînerait un état incohérent des objets en mémoire.Il existe deux différences principales.
Accéder aux côtés de l'association
Le premier est lié à la manière dont vous accéderez à la relation. Pour une association unidirectionnelle, vous pouvez naviguer dans l'association à partir d'une seule extrémité.
Ainsi, pour une
@ManyToOne
association unidirectionnelle , cela signifie que vous ne pouvez accéder à la relation que du côté enfant où réside la clé étrangère.Si vous avez une
@OneToMany
association unidirectionnelle , cela signifie que vous ne pouvez accéder à la relation que du côté parent où réside la clé étrangère.Pour l'
@OneToMany
association bidirectionnelle , vous pouvez naviguer dans l'association des deux manières, soit du côté parent, soit du côté enfant.Vous devez également utiliser des méthodes utilitaires d'ajout / suppression pour les associations bidirectionnelles afin de vous assurer que les deux côtés sont correctement synchronisés .
Performance
Le deuxième aspect est lié à la performance.
@OneToMany
, les associations unidirectionnelles ne fonctionnent pas aussi bien que les bidirectionnels .@OneToOne
, une association bidirectionnelle provoquera une récupération rapide du parent si Hibernate ne peut pas dire si le proxy doit être attribué ou une valeur nulle .@ManyToMany
, le type de collection fait toute la différence car il estSets
plus performant queLists
.la source
En termes de codage, une relation bidirectionnelle est plus complexe à mettre en œuvre car l'application est responsable de maintenir les deux côtés synchronisés conformément à la spécification JPA 5 (à la page 42). Malheureusement, l'exemple donné dans la spécification ne donne pas plus de détails, donc il ne donne pas une idée du niveau de complexité.
Lorsque vous n'utilisez pas de cache de deuxième niveau, il n'est généralement pas un problème de ne pas implémenter correctement les méthodes de relation car les instances sont supprimées à la fin de la transaction.
Lors de l'utilisation du cache de deuxième niveau, si quelque chose est corrompu en raison de méthodes de gestion des relations mal implémentées, cela signifie que les autres transactions verront également les éléments corrompus (le cache de deuxième niveau est global).
Une relation bidirectionnelle correctement implémentée peut simplifier les requêtes et le code, mais ne doit pas être utilisée si elle n'a pas vraiment de sens en termes de logique métier.
la source
Je ne suis pas sûr à 100% que ce soit la seule différence, mais c'est la principale différence. Il est également recommandé d'avoir des associations bidirectionnelles par la documentation Hibernate:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html
Plus précisément:
J'ai personnellement un léger problème avec cette recommandation générale - il me semble qu'il y a des cas où un enfant n'a aucune raison pratique de connaître son parent (par exemple, pourquoi un article de commande doit-il connaître la commande dont il s'agit? associé à?), mais j'y vois de la valeur dans une partie raisonnable du temps également. Et comme la bidirectionnalité ne fait vraiment aucun mal, je ne trouve pas cela trop répréhensible pour y adhérer.
la source