70 votes

Quand utiliser l’inverse = false sur NHibernate / Hibernate OneToMany relations ?

J'ai été d'essayer de se familiariser avec mise en veille prolongée de l'attribut inverse, et il semble être juste une de ces choses qui est conceptuellement difficile.

L'essentiel de l'information que je reçois est que lorsque vous avez une entité mère (Parents, par exemple), qui présente une collection d'objets Enfants à l'aide d'un un-à-plusieurs, la cartographie, la configuration inverse=true sur la cartographie indique à Hibernate de "l'autre côté (l'Enfant) a la responsabilité de mettre à jour lui-même pour maintenir la référence de clé étrangère dans son la table".

En faisant cela semble avoir 2 avantages quand il s'agit de l'ajout d'Enfants de la collection dans votre code, puis en enregistrant le Parent (avec cascade-tous ensemble): vous enregistrez une inutile de frapper sur la base de données (car sans inverse de jeu, Hibernate pense qu'il y a deux endroits pour mettre à jour le FK relation), et d'après les docs:

Si la colonne de l'association est déclarée PAS NULL, NHibernate peut provoquer les violations de contrainte lorsqu'il crée ou les mises à jour de l'association. Pour éviter ce problème, vous devez utiliser un bidirectionnel association avec l' beaucoup apprécié la fin (le jeu ou le sac) marqué comme inverse="true".

Tout cela semble de bon sens jusqu'à présent. Ce que je ne comprends pas, est ce: quand souhaitez-vous PAS souhaitez utiliser inverse=true sur un un-à-plusieurs relation?

82voto

Nigel Points 1487

Que Matthieu dit, le seul cas où vous ne souhaitez pas définir inverse = true est l'endroit où il ne fait pas de sens pour l'enfant à être responsable de la mise à jour de lui-même, comme dans le cas où l'enfant n'a pas connaissance de son parent.

Permet d'essayer un monde réel, et pas du tout artificiel, exemple:

<class name="SpyMaster" table="SpyMaster" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
  <set name="Spies" table="Spy" cascade="save-update">
    <key column="SpyMasterId"/>
    <one-to-many class="Spy"/>
  </set>
</class>

<class name="Spy" table="Spy" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
</class>

Spymasters peut avoir des espions, mais des espions ne sait jamais qui est leur maître-espion est, parce que nous n'avons pas inclus le many-to-one relation dans l'espion de classe. Aussi (idéalement) un espion peut tourner voyous et n'a donc pas besoin d'être associé avec un maître-espion. Nous pouvons créer des entités comme suit:

var sm = new SpyMaster
{
    Name = "Head of Operation Treadstone"
};
sm.Spies.Add(new Spy
{
    Name = "Bourne",
    //SpyMaster = sm // Can't do this
});
session.Save(sm);

Dans un tel cas, vous devez définir le FK colonne à nullable parce que l'acte de sauver sm à insérer dans le maître-espion de la table et l'Espion de la table, et seulement après que serait-il alors de mettre à jour l'Espion de la table pour définir la FK. Dans ce cas, si nous devions définir inverse = true, le FK ne serait jamais mis à jour.

29voto

Stefan Steinegger Points 37073

En dépit de la haute-voté accepté de répondre, j'ai une autre réponse à cette question.

Considérons un diagramme de classe avec ces relations:

Parent => liste des Articles
Item => Parent

Personne n'a jamais dit, que l'Article => relation est redondant à la Mère => les Éléments de relation. Un Élément pourrait renvoyer à n'importe quel Parent.

Mais dans votre application, vous savez que les relations sont redondantes. Vous savez que les relations n'ont pas besoin d'être enregistrées séparément dans la base de données. Vous décidez donc de le stocker dans une unique clé étrangère, pointant de l'Élément Parent. Ce minimum d'informations est assez pour construire la liste et les références.

Tout ce que vous devez faire pour cette carte avec NH est:

  • utiliser la même clé étrangère pour les deux relations
  • dites-NH que l'un (la liste) est redondant à l'autre et peut être ignorée lors de l'entreposage de l'objet. (C'est ce que NH fait effectivement de inverse="true")

Telles sont les pensées qui sont pertinentes pour l'inverse. Rien d'autre. Ce n'est pas un choix, il n'y a qu'une seule façon de corriger la cartographie.


L'Espion Problème: C'est une toute autre discussion si vous souhaitez soutenir une référence à partir de l'Élément Parent. C'est à votre modèle d'affaires, l'hôtel NH ne pas prendre toute décision dans ce. Si l'une des relations est manquant, il n'y a évidemment pas de redondance et aucune utilisation de l'inverse.

Abus: Si vous utilisez l'inverse="true" sur une liste qui n'ont pas de redondance dans la mémoire, il n'est pas stocké. Si vous ne spécifiez pas l'inverse="true" si elle doit être là, NH peut stocker les informations redondantes deux fois.

15voto

Matthieu Points 2766

Si vous voulez avoir une association unidirectionnelle, c'est-à-dire que les enfants ne peuvent pas naviguer au Parent. Dans l’affirmative, vous colonne FK devrait être NULLABLE parce que les enfants seront enregistrées avant le parent.

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