¿Cuándo usar inverse = false en las relaciones NHibernate / Hibernate OneToMany?


He estado tratando de entender el atributo inverso de Hibernate, y parece ser solo una de esas cosas que es conceptualmente difícil.

La esencia que obtengo es que cuando tiene una entidad padre (por ejemplo, Padre) que tiene una colección de objetos Hijos usando una asignación de uno a muchos, establecer inverse=true en la asignación le dice a Hibernate que 'el otro lado (el Hijo) tiene la responsabilidad de actualizarse para mantener la referencia de clave foránea en su tabla'.

Hacer esto parece tener 2 beneficios cuando se trata de agregar Hijos a la colección en su código, y luego guardar el Padre (con cascade-all set): guarda un hit innecesario en la base de datos (porque sin inverse set, Hibernate piensa que tiene dos lugares para actualizar la relación FK), y según los documentos oficiales:

Si la columna de a se declara la asociación NULL, NHibernate puede causar violaciones de restricción cuando crea o actualiza la asociación. Prevenir este problema, debe utilizar un asociación bidireccional con el muchos finales valorados (el conjunto o bolsa) marcado como inverse="true".

Todo Esto parece tener sentido hasta ahora. Lo que no entiendo es esto: ¿cuándo NO querrías usar inverse=true en una relación de uno a muchos?

Author: James Allen, 2009-06-30

3 answers

Como dice Matthieu, el único caso en el que no querría establecer inverse = true es donde no tiene sentido que el hijo sea responsable de actualizarse a sí mismo, como en el caso en el que el hijo no tiene conocimiento de su padre.

Vamos a probar un mundo real, y no en absoluto artificial ejemplo:

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

Los espías pueden tener espías, pero los espías nunca saben quién es su espías, porque no hemos incluido la relación de muchos a uno en la clase de espías. También (convenientemente) un espía puede convertirse en pícaro y por lo tanto no necesita ser asociado con un spymaster. Podemos crear entidades de la siguiente manera:

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);

En tal caso, establecería la columna FK para que sea nullable porque el acto de guardar sm se insertaría en la tabla SpyMaster y en la tabla Spy, y solo después de eso actualizaría la tabla Spy para establecer el FK. En este caso, si tuviéramos que establecer inverse = true, el FK nunca se actualizaría.

 81
Author: Nigel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-13 12:09:32

A pesar de la respuesta altamente votada y aceptada, tengo otra respuesta a eso.

Considere un diagrama de clases con estas relaciones:

Parent => list of Items
Item => Parent

Nadie nunca dijo que la relación Item => Parent es redundante con la relación Parent => Items. Un Elemento podría hacer referencia a cualquier Padre.

Pero en su solicitud, sabe que las relaciones son redundantes. Usted sabe que las relaciones no necesitan ser guardadas separadamente en la base de datos. Así que decide almacenarlo en una clave externa única, apuntando desde el Elemento al Padre. Esta información mínima es suficiente para construir la lista y la referencia.

Todo lo que necesitas hacer para mapear esto con NH es:

  • utilice la misma clave foránea para ambas relaciones
  • dile a NH que uno (la lista) es redundante para el otro y podría ser ignorado al almacenar el objeto. (Eso es lo que NH realmente hace con inverse="true")

Estos son los pensamientos que son relevantes para inverso. Nada más. No es una elección, solo hay una forma de mapear correctamente.


El Problema de los Espías: Es una discusión completamente diferente si desea admitir una referencia del Elemento al Padre. Esto depende de su modelo de negocio, NH no toma ninguna decisión al respecto. Si falta una de las relaciones, por supuesto no hay redundancia ni uso de inversa.

Mal uso: Si utiliza inverse = "true" en una lista que no tener cualquier redundancia en la memoria, simplemente no se almacena. Si no especifica el inverse = "true" si debería estar allí, NH puede almacenar la información redundante dos veces.

 29
Author: Stefan Steinegger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-10 13:02:45

Si desea tener una asociación unidireccional, es decir, que los hijos no puedan navegar al Padre. Si es así, su columna FK debería ser NULLABLE porque los hijos se guardarán antes que el padre.

 14
Author: MatthieuGD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 20:57:52