2010-02-16 13 views
5

Tengo una relación padre-hijo entre dos entidades (padre e hijo).Eliminar un elemento de una colección (NHibernate)

Mi padre de mapeo es el siguiente:

<class name="Parent" table="Parents"> 
    ... 
    <bag name="Children" cascade="all"> 
     <key column="ParentID"></key> 
     <one-to-many class="Child"></one-to-many> 
    </bag> 
</class> 

me gustaría ejecutar lo siguiente:

someParent.Children.Remove(someChild); 

La clase del niño tiene una referencia a otra clase padre, Tipo. La relación parece

relation diagram

Nota: Me disculpo por la url no relacionado anteriormente, yo no era capaz de superar el asterisco en la cadena URL usando marcado

Debido a esta relación, cuando se llama al código anterior, en lugar de una consulta DELETE, se genera una consulta UPDATE que elimina el ParentID de la tabla Child (establece en nulo).

¿Es posible obligar a NHibernate a eliminar por completo el registro secundario cuando se lo retira de la colección Parent.Children?

ACTUALIZACIÓN

@ Solución

solución muy atractiva de Spencer ya que esto es algo que puede ser implementado en las clases futuras. Sin embargo, debido a la forma en que se manejan las sesiones (en mi caso particular) en el patrón de repositorio, esto es casi imposible, ya que tendríamos que pasar los tipos de sesión (CallSessionContext/WebSessionContext) dependiendo de la aplicación.

@ simple y rápido de implementar, sin embargo, me he pegado a otro obstáculo en el camino de soluciones

de Jamie. Mi entidad hijo tiene el siguiente aspecto: entity object

Al usar el nuevo método, NHibernate genera una declaración de actualización que establece el TypeID y ParentID como nulo, en lugar de un solo borrado completo. Si me perdí algo dentro de la implementación, hágamelo saber ya que este método sería fácil de seguir.

@The One-Shot-Delete solution described here, describe una idea para desreferenciar la colección para forzar una sola eliminación. Los mismos resultados que arriba, sin embargo, se emite una declaración de actualización.

//Instantiate new collection and add persisted items 
List<Child> children = new List<Child>(); 
children.AddRange(parent.Children); 

//Find and remove requested items from new collection 
var childrenToRemove = children 
    .Where(c => c.Type.TypeID == 1) 
    .ToList(); 

foreach (var c in childrenToRemove) { children.Remove(m); } 
parent.Children = null; 

//Set persisted collection to new list 
parent.Children = Children; 

Solución

tomó un poco de excavación, pero la solución de Jamie vino a través de algunas modificaciones adicionales. Para los futuros lectores, basado en mi modelo de clase superior:

asignación de tipo - Inverse = true, Cascade = all

mapeo de Padres - Inverse = true, Cascade = all-delete-orphan

Retire métodos descrito en los trabajos de solución de Jamie.Esto produce una sola declaración de eliminación por artículo huérfano, por lo que existe la posibilidad de ajuste en el futuro, sin embargo, el resultado final es exitoso.

Respuesta

1

En lugar de exponer la IList<Child>, controlar el acceso a la colección a través de un método:

RemoveChild(Child child) 
{ 
    Children.Remove(child); 
    child.Parent = null; 
    child.Type.RemoveChild(child); 
} 

Type.RemoveChild tendría un aspecto similar, pero que tendría que tener cuidado de no poner en un bucle infinito llamarse unos a otros de Métodos RemoveChild.

0

No creo que esto sea exactamente posible porque Hibernate no tiene forma de saber si el registro ha quedado huérfano. Puede verificar si otras clases se relacionan con la clase secundaria pero supondría que conoce la estructura completa de la BD, que puede no ser el caso.

Sin embargo, no está del todo sin suerte. Al usar la interfaz IList junto con una interfaz ICascadeDeleteChild personalizada que crearía, puede encontrar una solución bastante sencilla. Aquí están los pasos básicos.

  1. Crear una clase que inheirits IList y IList <> y llamarlo CascadeDeleteList o algo por el estilo.
  2. Crea una lista .Net privada dentro de esta clase y simplemente realiza un proxy de las diversas llamadas a esta lista.
  3. Cree una interfaz llamada ICascadeDeleteChild y dele un método Delete()
  4. Con el método Delete para su CascadeDeleteList, compruebe el tipo del objeto que se va a eliminar. Si es de tipo ICascadeDeleteChild, llámalo Método de eliminación.
  5. Cambie su clase secundaria para implementar la interfaz ICascadeDeleteChild.

Sé que parece una molestia, pero una vez hecho esto, estas interfaces deben ser fáciles de transportar.

+0

Creo que esto puede haberme impulsado en el camino correcto, siendo los bloques de ruta: configurar esto en un patrón de repositorio (es decir, en este caso el método Child Delete llamaría a su propio método repositorio) y también poder usar esto con diferentes contextos de sesión (es decir, CallSessionContext vs WebSessionContext) –

Cuestiones relacionadas