168 votes

Quelle est la différence entre les associations JPA et Hibernate unidirectionnelles et bidirectionnelles ?

Quelle est la différence entre les associations unidirectionnelles et bidirectionnelles ?

Puisque les tables générées dans la base de données sont toutes les mêmes, la seule différence que j'ai trouvée est que chaque côté des associations bidirectionnelles aura une référence à l'autre, et les unidirectionnelles non.

Il s'agit d'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 détient une référence de l'utilisateur.

Je me demande donc si c'est la seule différence ? laquelle est recommandée ?

11 votes

Le groupe saura désormais quels utilisateurs il contient. Je ne pense pas qu'il s'agisse d'une différence minime, loin de là.

7 votes

Les relations bidirectionnelles sont devenues un chaos pour moi lorsqu'il s'agit de mettre à jour :)

0 votes

Cela peut aider : thorben-janssen.com/

183voto

axtavt Points 126632

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. Elle vous permet également d'appliquer des options en cascade aux deux directions.

Notez que l'accès par navigation n'est pas toujours bon, en particulier pour les relations "one-to-very-many" et "many-to-very-many". Imaginez un Group qui contient des milliers de User s :

  • Comment y accéder ? Avec tant de User vous devez généralement appliquer un filtrage et/ou une pagination, de sorte que vous devez de toute façon exécuter une requête (à moins que vous n'utilisiez l'option filtrage des collections qui ressemble à un hack pour moi). Certains développeurs peuvent avoir tendance à appliquer le filtrage en mémoire dans de tels cas, ce qui n'est évidemment pas bon pour les performances. Notez que l'existence d'une telle relation peut encourager ce type de développeurs à l'utiliser sans tenir compte des conséquences sur les performances.

  • Comment ajouter de nouvelles User à la Group ? Heureusement, Hibernate prend en compte le côté propriétaire de la relation lorsqu'il la persiste, de sorte que vous ne pouvez définir que les éléments suivants User.group . Cependant, si vous souhaitez que les objets en mémoire restent cohérents, vous devez également ajouter le paramètre User a Group.users . Mais cela obligerait Hibernate à aller chercher tous les éléments de Group.users de la base de données !

Donc, je ne peux pas être d'accord avec la recommandation de la Meilleures pratiques . Vous devez concevoir les 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 éventuelles répercussions sur les performances.

Voir aussi :

0 votes

Bonjour, merci, il semble que vous soyez un expert d'Hibernate, puisque vous avez répondu à ma question : stackoverflow.com/questions/5350770/ . Et maintenant, je ne suis pas sûr que la relation tienne, puisque je ne peux pas écrire plus dans le commentaire, alors je le poste ici. dpaste.de/J85m Veuillez vérifier si possible :)

0 votes

@hguser : Si vous décidez finalement de rendre votre relation bidirectionnelle, je pense qu'il serait préférable d'appeler setGroup() de addUser() afin d'assurer la cohérence des deux côtés.

0 votes

Et si je n'appelle pas le setGroup() à l'intérieur du group.addUser() ?

43voto

Vlad Mihalcea Points 3628

Il y a deux différences principales.

Accéder aux côtés de l'association

La première est liée à 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é.

Donc, pour un unidirectionnel @ManyToOne cela signifie que vous ne pouvez accéder à la relation qu'à partir du côté enfant où réside la clé étrangère.

Si vous disposez d'un système unidirectionnel @OneToMany cela signifie que vous ne pouvez accéder à la relation qu'à partir du côté parent qui gère la clé étrangère.

Pour le système bidirectionnel @OneToMany vous pouvez naviguer dans l'association dans les deux sens, soit du côté du parent, soit du côté de l'enfant.

Vous devez également utiliser des méthodes utilitaires d'ajout/suppression pour les associations bidirectionnelles afin de s'assurer que les deux côtés sont correctement synchronisés .

Performance

Le deuxième aspect est lié à la performance.

  1. Pour @OneToMany , Les associations unidirectionnelles ne sont pas aussi performantes que les associations bidirectionnelles. .
  2. Pour @OneToOne , une association bidirectionnelle entraînera une recherche rapide du parent si Hibernate n'est pas en mesure de déterminer si le proxy doit être attribué ou s'il s'agit d'une valeur nulle. .
  3. Pour @ManyToMany , le type de collection fait une grande différence car Sets sont plus performants que Lists .

0 votes

Mais le côté parent est toujours celui qui a la clé étrangère, pour autant que je sache. Ces deux phrases me semblent contradictoires. from the child side where the foreign key resides. from the parent side where the foreign key resides.

1 votes

Le FK est toujours du côté de l'enfant. Le OneToMany unidirectionnel gère le FK qui peut être dans la table enfant ou dans une table de jointure. Suivez les liens pour plus de détails.

11voto

En termes de codage, une relation bidirectionnelle est plus complexe à mettre en œuvre car l'application est responsable de la synchronisation des deux parties, conformément à la spécification 5 de JPA (page 42). Malheureusement, l'exemple donné dans la spécification ne donne pas plus de détails, il ne permet donc pas de se faire une idée du niveau de complexité.

Lorsqu'on n'utilise pas de cache de second niveau, il n'y a généralement pas de problème à ne pas mettre en œuvre correctement les méthodes de relation, car les instances sont éliminées à la fin de la transaction.

Lorsque vous utilisez le cache de deuxième niveau, si un élément est corrompu en raison de méthodes de gestion des relations mal mises en œuvre, cela signifie que les autres transactions verront également les éléments corrompus (le cache de deuxième niveau est global).

Une relation bidirectionnelle correctement mise en œuvre 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 commerciale.

11voto

kvista Points 3681

Je ne suis pas sûr à 100% que ce soit le uniquement différence, mais c'est la principal différence. La documentation d'Hibernate recommande également d'avoir des associations bidirectionnelles :

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

Plus précisément :

Préférez les associations bidirectionnelles : Les associations unidirectionnelles sont plus difficiles à interroger. Dans une grande application, presque toutes les associations doivent être navigables dans les deux sens dans les requêtes.

Personnellement, j'ai 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 élément de commande Necesito pour connaître l'ordre auquel il est associé ?), mais j'y vois aussi de la valeur une partie raisonnable du temps. Et comme la bidirectionnalité ne nuit pas vraiment à quoi que ce soit, je ne trouve pas qu'il soit trop difficile d'y adhérer.

0 votes

La bidirectionnalité peut nuire dans certains cas, comme l'a expliqué axtavt ! Je serais très prudent avec chaque relation mappée dans une entité Hibernate ! Vous pouvez vous retrouver avec un temps interminable pour charger les choses dans Hibernate, sauf si vous savez exactement ce que vous faites. Réfléchissez soigneusement aux cas d'utilisation et utilisez différentes classes de modèles pour différents cas d'utilisation. Par exemple, dans une liste de choses, je n'ai pas besoin de tous les objets liés, juste une étiquette et l'ID. L'entité liste est donc différente (et très simple) de l'entité détail, pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X