web-dev-qa-db-fra.com

Quelle est la différence entre les associations JPA unidirectionnelle et bidirectionnelle et Hibernate?

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

Comme la table générée dans la base de données est identique, la seule différence que j’ai trouvée est que chaque côté des associations bidirétionnelles aura une référence à l’autre, et l’unidirectionnel non.

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é?

120
hguser

La principale différence réside dans le fait que la relation bidirectionnelle fournit un accès à la navigation dans les deux sens, de sorte que vous pouvez accéder à l'autre côté sans requêtes explicites. En outre, cela 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 nombreux" et "plusieurs à très nombreux". Imaginez un Group contenant des milliers de Users:

  • Comment y accéderiez-vous? Avec autant de Users, vous devez généralement appliquer un filtrage et/ou une pagination afin d'exécuter une requête quand même (sauf si vous utilisez filtrage de la collection , 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 qu'une telle relation peut encourager ce type de développeurs à l'utiliser sans prendre en compte les implications en termes de performances.

  • Comment ajouteriez-vous le nouveau Users au Group? Heureusement, Hibernate examine le côté propriétaire de la relation lorsqu'il la persiste. Vous ne pouvez donc définir que User.group. Toutefois, si vous souhaitez conserver des objets en mémoire cohérents, vous devez également ajouter User à Group.users. Mais cela rendrait Hibernate chercher tous les éléments de Group.users de la base de données!

Je ne peux donc pas accepter la recommandation de Meilleures pratiques . Vous devez concevoir les relations bidirectionnelles avec soin, en tenant compte des cas d'utilisation (avez-vous besoin d'un accès à la navigation dans les deux sens?) Et des conséquences possibles sur les performances.

Voir aussi:

132
axtavt

Il y a deux différences principales.

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

Le premier est lié à la manière dont vous allez accéder à la relation. Pour une association unidirectionnelle, vous pouvez naviguer dans l’association d’un seul côté.

Ainsi, pour une association unidirectionnelle @ManyToOne, 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 association unidirectionnelle @OneToMany, Cela signifie que vous ne pouvez accéder à la relation que du côté parent où réside la clé étrangère.

Pour l'association bidirectionnelle @OneToMany, Vous pouvez naviguer dans l'association de deux manières, du parent ou du côté enfant.

Vous devez également tilisez les 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.

  1. Pour @OneToMany, les associations unidirectionnelles ne fonctionnent pas aussi bien que celles bidirectionnelles .
  2. Pour @OneToOne, ne association bidirectionnelle provoquera l'extraction rapide du parent si Hibernate ne peut pas dire si le proxy doit être attribué ou une valeur nulle .
  3. Pour @ManyToMany, le type de collection fait toute une différence, car Sets a de meilleurs résultats que Lists .
18
Vlad Mihalcea

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

Lorsque vous n'utilisez pas de cache de second niveau, le fait de ne pas correctement implémenter les méthodes de relation ne constitue généralement pas un problème, car les instances sont supprimées à la fin de la transaction.

Lors de l'utilisation du cache de second niveau, si quelque chose est corrompu en raison de méthodes de traitement de relation mal implémentées, cela signifie que d'autres transactions verront également les éléments corrompus (le cache de second 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.

10

Je ne suis pas sûr à 100% que ce soit la différence seulement , mais c'est la différence principale différence. Il est également recommandé d’avoir des associations bidirectionnelles de la part des documents Hibernate:

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, cette recommandation générale me pose un léger problème - il me semble qu’il existe des cas où un enfant n’a aucune raison pratique de connaître son parent (par exemple, pourquoi un article de commande besoin de connaître l'ordre dans lequel il est associé?), mais j'y vois aussi une valeur raisonnable une bonne partie du temps. Et puisque la bidirectionnalité ne fait vraiment pas de mal, je ne trouve pas cela trop désagréable d'adhérer.

9
kvista