Pregunta

Tengo una relación de muchos a uno entre los objetos Producto y Proveedor . Necesito poder eliminar el Proveedor sin eliminar los Producto que le pertenecen.

Aquí hay una versión simplificada de las clases:

public class Supplier {
    public virtual IList<Product> Products { get; protected set; }
}

public class Product {
    // Product belongs to a Category but Supplier is optional
    public virtual Supplier Supplier { get; set; }
    public virtual Category Category { get; set; }
}

Estoy usando FluentNHibernate, pero aquí están las asignaciones que produce:

<bag name="Products" cascade="save-update" inverse="true">
      <key column="SupplierID" />
      <one-to-many class="Me.Product, Me, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>

<many-to-one name="Supplier" column="SupplierID" />

Esto crea una clave foránea en la tabla Productos, por lo que cuando intento hacer una eliminación directa en un Proveedor obtengo un error de restricción de clave foránea. Intenté cambiar la cascada a 'todos', con la esperanza de que solo pudiera eliminar la relación, pero eliminó todos los Productos y sus otros objetos asociados.

La única forma en que puedo ver para resolver esto ahora es iterar la colección de Productos del Proveedor y establecer la propiedad Proveedor en nula. ¿Hay alguna manera de lograr este comportamiento a través del mapeo?

¿Fue útil?

Solución

Las propiedades de mapeo solo surten efecto cuando la entidad está realmente cargada y cuando no realiza consultas a través de HQL. Como ejemplo, si especifica Cascade = ALL , si elimina un proveedor con la consulta " delete from Supplier donde id =: id " , probablemente obtendrá el mismo fallo de restricción FK, porque hql no activa cascadas (programáticas).

Parece que los Productos son el lado propietario de la relación, lo cual es bueno. Creo que tienes dos opciones:

  • Codifique algún método en el Proveedor para iterar a través de todos los Productos y establezca el proveedor del Producto en nulo, y use este método antes de eliminar cualquier Proveedor
  • Antes de emitir una eliminación de Proveedor, asegúrese de que su DAO establece el proveedor del producto en nulo

Ejemplo:

public int Delete(Supplier s) {
    return Session.CreateQuery("udpate Product set Supplier = null where Supplier = :supplier")
        .SetParameter("supplier", s)
        .ExecuteUpdate();
}

Otros consejos

NO HAGA ESTO.

Usted tiene una afirmación implícita o explícita en su modelo de que todos los Productos tienen un Proveedor. La clave foránea está ahí para hacer cumplir esta condición. La eliminación del Proveedor mientras se mantienen los Productos viola su modelo y probablemente hará que gran parte de su código, que se basa en que esto sea siempre cierto, falle.

Lo único que puede hacer, ya lo ha descubierto: por cada Producto que tenga este Proveedor, puede establecer el Proveedor del Producto como nulo. Esto no violará su condición, pero es lo mismo que decir "no sabemos quién es el proveedor de este producto". y puede causar fallas en el código.

¿Por qué quieres hacer esto?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top