¿Cómo eliminar un objeto secundario en NHibernate?


Tengo un objeto padre que tiene una relación de uno a muchos con un IList de objetos hijos. ¿Cuál es la mejor manera de eliminar los objetos secundarios? No voy a borrar al padre. Mi objeto padre contiene una lista de objetos hijos. Aquí está el mapeo para la relación uno a muchos:

<bag name="Tiers" cascade="all">
  <key column="mismatch_id_no" />
  <one-to-many class="TGR_BL.PromoTier,TGR_BL"/>
</bag>

Si intento eliminar todos los objetos de la colección usando clear (), entonces llamo a saveOrUpdate (), obtengo esta excepción:

System.Data.SqlClient.SqlException: Cannot insert the value NULL into column

Si intento eliminar los objetos secundarios individualmente, entonces eliminarlos del padre, obtengo una excepción:

deleted object would be re-saved by cascade

Esta es mi primera vez tratando con la eliminación de objetos secundarios en NHibernate. ¿Qué estoy haciendo mal?

Editar: Solo para aclarar - NO estoy tratando de eliminar el objeto padre, solo los objetos hijos. Tengo la relación establecida como uno a muchos en el padre. ¿También necesito crear una relación de muchos a uno en la asignación de objetos secundarios?

 77
Author: Mark Struzinski, 2008-11-19

6 answers

Está recibiendo el primer error porque, cuando elimina los elementos de la colección, el modo de operación predeterminado de NHibernate es simplemente romper la asociación. En la base de datos, NHibernate intenta establecer la columna de clave foránea en la fila secundaria en null. Dado que no permite valores nulos en esa columna, SQL Server genera el error. Borrar la colección no necesariamente borrará el objeto hijo, pero una forma de hacerlo es establecer cascade=all-delete-orphan. Esto informa a NHibernate que debe eliminar las filas recién huérfanas en lugar de establecer la columna de clave externa.

Está recibiendo el segundo error porque cuando llama a saveOrUpdate NHibernate primero elimina todos los objetos secundarios. Entonces, debido a que ninguna relación está marcada como inversa, NHibernate también intenta establecer la columna de clave foránea en su tabla secundaria en null. Dado que las filas ya se han eliminado, recibe el segundo error. Necesitas establecer inverse = true en un lado de tu relación para arreglar esto. Esto generalmente se hace en el lado uno (clave primaria o padre). Si no lo hace, NHibernate hará las actualizaciones apropiadas para cada lado de la relación. Desafortunadamente, ejecutar dos actualizaciones no es lo apropiado.

Siempre debe marcar un lado de sus relaciones como el lado inverso. Dependiendo de cómo codifique, puede o no necesitar usar cascada. Si desea aprovechar las eliminaciones de one shot como está tratando de hacer con Clear(), debe define tu cascada.

 134
Author: Chuck,
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-01-02 16:23:52

De acuerdo con la respuesta de Chuck, he resuelto mi problema agregando Inverse = true en la asignación del lado padre:

El mensaje tiene muchos MessageSentTo:

[HasMany(typeof(MessageSentTo), Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true)]
public IList<MessageSentTo> MessageSendTos
{
    get { return m_MessageSendTo; }
    set { m_MessageSendTo = value; }
}

Estoy usando Castle ActiveRecord. Gracias Chuck.

 3
Author: hanuman0503,
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
2010-07-23 09:59:00

Intenta usar merge() en lugar de saveOrUpdate(). Además, asegúrese de que su cascada está establecida en all-delete-orphan y que su relación padre-hijo es invertible (inverse=true en el padre y luego un campo en el hijo que es el padre-id con not-null=true).

 2
Author: Elie,
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
2008-11-19 17:58:45

En nuestro ejemplo tenemos categorías con muchos productos donde un producto no es nullable.

Puede solucionar el problema eliminando el producto y eliminándolo de la colección principal antes de la descarga, pero todavía estamos buscando una mejor solución para esto.

product = pRepo.GetByID(newProduct.ProductID);
product.Category.Products.Remove(product);
pRepo.Delete(product);

Espero que ayude de todos modos

 2
Author: Liath,
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
2010-05-27 16:31:05

Cambie el valor del atributo cascade de "all" a "all-delete-orphan".

 0
Author: Thomas Tekavec,
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
2008-11-19 17:49:47

Establezca Not-Null = true en su asignación en la columna que causa el problema. Aunque no estoy seguro de la sintaxis exacta (lo siento).

 -3
Author: Kyle West,
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
2008-11-19 17:43:16