¿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 tienes una entidad padre (por ejemplo, Parent) que tiene una colección de objetos Child usando un mapeo de uno a muchos , al establecer inverse = true en el mapeo le dice a Hibernate que ‘el otro lado (el Niño ) tiene la responsabilidad de actualizarse para mantener la referencia de clave externa en su tabla ‘.

Hacer esto parece tener 2 beneficios cuando se trata de agregar Niños a la colección en su código y luego guardar el Padre (con todo en cascada): guarda un golpe innecesario en la base de datos (porque sin conjunto inverso, Hibernate lo piensa tiene dos lugares para actualizar la relación FK), y de acuerdo con los documentos oficiales:

Si la columna de una asociación se declara NOT NULL, NHibernate puede causar violaciones de restricciones cuando crea o actualiza la asociación. Para evitar este problema, debe usar una asociación bidireccional con los muchos extremos valorados (el conjunto o la bolsa) marcado como inverso = “verdadero”.

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

Como dice Matthieu, el único caso en el que no desearía establecer reverse = true es cuando no tiene sentido que el niño sea responsable de la actualización, como en el caso en que el niño no tiene conocimiento de su padre.

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

                

Los espías pueden tener espías, pero los espías nunca saben quién es su espía, 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 delincuente y por lo tanto no necesita estar asociado con un jefe de espías. 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 que la columna FK sea anulable porque el acto de guardar sm se insertaría en la tabla de SpyMaster y en la tabla de Spy, y solo después de eso actualizaría la tabla de Spy para configurar el FK. En este caso, si tuviéramos que establecer inverso = verdadero, el FK nunca se actualizaría.

A pesar de la respuesta aceptada de alta votación, tengo otra respuesta a eso.

Considere un diagtwig de clase con estas relaciones:

 Parent => lista de elementos
 Artículo => Padre

Nadie dijo nunca , que la relación Item => Parent es redundante para la relación Parent => Items. Un artículo podría hacer referencia a cualquier padre.

Pero en su aplicación, usted sabe que las relaciones son redundantes . Usted sabe que las relaciones no necesitan almacenarse por separado en la base de datos. Por lo tanto, decide almacenarlo en una sola clave externa , apuntando desde el elemento al elemento principal. Esta información mínima es suficiente para construir la lista y la referencia de vuelta.

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

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

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


El problema del espía : es una discusión completamente diferente si desea respaldar una referencia del artículo 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.

Uso incorrecto: si usa inverse = “true” en una lista que no tiene redundancia en la memoria, simplemente no se almacena. Si no especifica el inverso = “verdadero” si debería estar allí, NH puede almacenar la información redundante dos veces.

Si desea tener una asociación unidireccional, es decir, que los niños no puedan navegar hacia el Padre. Si es así, la columna FK debe ser NULLABLE porque los hijos se guardarán antes que el padre.