Pregunta

Tengo un objeto llamado "Cliente", que se utiliza en las otras tablas como claves externas.

El problema es que yo quiero saber si se puede eliminar un "cliente" (es decir, no se está haciendo referencia en ninguna otra tabla).

¿Es esto posible con Nhibernate?

¿Fue útil?

Solución

Lo que se está pidiendo es encontrar la existencia del valor PK Customer en la columna de tablas referenciadas FK. Hay muchas maneras en que puede ir sobre esto:

  1. como se ha indicado kgiannakakis, tratar de hacer el borrado y si se produce una excepción de reversión. Eficaz, pero feo y no es útil. Esto también requiere que haya establecido una cascada = "Prohibir" en su base de datos. Esta solución tiene el inconveniente de que hay que tratar de eliminar el objeto de averiguar que no se puede

  2. Mapa de las entidades que hacen referencia a Customer como colecciones y luego para cada colección si su Count > 0 entonces no permiten la eliminación. Esto es bueno porque esto es seguro contra los cambios de esquema siempre que el mapeo es completa. También es una mala solución porque selecciona adicionales tendrán que ser hecho.

  3. Tener un método que realiza una consulta como bool IsReferenced(Customer cust). Bueno porque usted puede tener una sola consulta que va a utilizar cuando se desea. No tan bueno, ya que puede ser susceptible a errores debido a esquema y / o cambios de dominio (en función del tipo de consulta que va a hacer: SQL / HQL / criterios).

  4. Una propiedad computada en sí es clase con un elemento de mapeo como <property name="IsReferenced" type="long" formula="sql-query that sums the Customer id usage in the referenced tables" />. Buena porque es una solución rápida (al menos tan rápido como su base de datos es), no hay consultas adicionales. No tan bueno, ya que es susceptible a cambios en el esquema modo que cuando cambie su base de datos no hay que olvidar a actualizar esta consulta.

  5. solución loco: crear una vista con destino esquema que hace el cálculo. Realizar la consulta en él cuando lo desee. Bien porque su esquema de ruedas y es menos susceptible a los cambios de esquema, bien porque la consulta es rápida, no tan buena, ya que todavía tiene que hacer una consulta adicional (o asigna el resultado de este punto de vista en solución al 4).

2,3,4 también son buenos porque también se puede proyectar este comportamiento de la interfaz de usuario (no permita que el borrado)

En lo personal me gustaría ir para que la preferencia con 4,3,5

Otros consejos

  

Me gustaría saber si se puede eliminar un "cliente" (es decir, no se está haciendo referencia en ninguna otra tabla).

En realidad no es la responsabilidad de base de datos para determinar si el cliente se puede eliminar. Es más bien parte de su lógica de negocio .

Se le solicita que verifique la integridad referencial en la base de datos.

No está mal en el mundo no programación orientada a objetos. Pero cuando se trata de objetos (como lo hace) que añadir mejor la lógica de sus objetos ( objetos tienen estado y el comportamiento; DB - sólo el estado ).

Por lo tanto, me gustaría añadir un método a la clase de cliente para determinar si se puede eliminar o no. De esta manera usted puede adecuadamente (unidad) probar la funcionalidad .

Por ejemplo, supongamos que tenemos una regla Cliente sólo puede ser borrado si no tiene órdenes y no ha participado en el foro .

A continuación, tendrá objeto Cliente similar a este (caso más simple posible):

public class Customer
{
    public virtual ISet<Order> Orders { get; protected set; }
    public virtual ISet<ForumPost> ForumPosts { get; protected set; }

    public virtual bool CanBedeleted
    {
        get
        {
            return Orders.Count == 0 && ForumPosts.Count == 0
        }
    }
}

Éste es diseño muy limpio y simple que es fácil de usar, probar y no depende en gran medida NHibernate o base de datos subyacente.

Puede utilizar de esta manera:

if (myCustomer.CanBeDeleted)
    session.Delete(mycustomer)

Además de que se puede afinar NHibernate para borrar las órdenes relacionadas y otras asociaciones, si es necesario.


La nota: por supuesto, el ejemplo anterior es sólo ilustrativa solución más simple posible. Es posible que desee hacer una la validación que se deben cumplir cuando se elimina el objeto.

Pensando en las entidades y relaciones en lugar de tablas y las claves externas, existen estas situaciones diferentes:

  • El cliente tiene una relación de uno a muchos, que construye una parte del cliente, por ejemplo, sus números de teléfono. También deben ser eliminados por medio de cascada.
  • El cliente tiene a.
  • uno-a-muchos o muchos a-muchos relación que no es parte del cliente, pero son conocidos / accesible por el cliente
  • alguna otra entidad tiene una relación con el cliente. También podría ser un tipo cualquiera (que no es una clave externa en la base de datos). Por ejemplo, las órdenes del cliente. Las órdenes no son conocidos por el cliente. Este es el caso más difícil.

Por lo que yo sé, no hay una solución directa de NHibernate. Existe la API de meta-datos, lo que le permite explorar las definiciones de asignación en tiempo de ejecución. En mi humilde opinión, esta es la manera incorrecta de hacerlo.

En mi opinión, es el responsabilidad de la lógica de negocio para validar si una entidad se puede eliminar o no. (Incluso si hay claves externas y las limitaciones que asegura la integridad de la base de datos, sigue siendo la lógica de negocio).

Hemos puesto en marcha un servicio que se llama antes de la eliminación de una entidad. Otras partes del software se registran para ciertos tipos. Pueden veto en contra de la eliminación (por ejemplo. Lanzando una excepción).

Por ejemplo, el sistema de orden registra para su eliminación de los clientes. Si un cliente debe ser borrado, el sistema busca en orden para las órdenes de este cliente y lanza si se encontró uno.

No es posible directamente. Es de suponer que su modelo de dominio incluye objetos relacionados del cliente, tales como direcciones, órdenes, etc. Usted debe utilizar el patrón especificación para esto.

public class CustomerCanBeDeleted
{

    public bool IsSatisfiedBy(Customer customer)
    {
        // Check that related objects are null and related collections are empty
        // Plus any business logic that determines if a Customer can be deleted
    }
}

Editado para añadir:

Tal vez el método más sencillo sería crear un procedimiento almacenado que realiza esta comprobación y llame antes de eliminar. Puede acceder a una IDbCommand de NHibernate (ISession.Connection.CreateCommand()) para que la llamada es la base de datos agnóstico.

Vea también las respuestas a esta pregunta .

Puede ser que sea digno de mirar la propiedad en cascada, en particular, todo-delete-orphan en sus archivos hbm.xml y esto puede cuidar de él para usted.

Ver aquí, 16,3 - Ciclo de vida en cascada

Una solución ingenua será utilizar una transacción. Iniciar una transacción y eliminar el objeto. Una excepción le informará de que el objeto no se puede eliminar. En cualquier caso, hacer un roll-back.

en el mapa los entidades que hacen referencia al cliente como colecciones. Nombre cada colección en su clase de cliente con un ejemplo particular suffix.For si su entidad cliente tiene algunas órdenes, el nombre de la colección de la siguiente manera Órdenes:

public virtual ISet<Order> Orders_NHBSet { get; set; } // add "_NHBSet" at the end 

Ahora mediante el uso de la reflexión puede obtener todas las propiedades de cliente en tiempo de ejecución y obtener las propiedades que sus nombres termina con el sufijo definido (en este caso "_NHBSet") se debe comprobar cada colección si contienen ningún elemento y si es así evitar la supresión de los clientes.

public static void DeleteCustomer(Customer customer)
{
   using (var session = sessions.OpenSession())
   {
       using (var transaction = session.BeginTransaction())
       {

           var listOfProperties =typeof(Customer).GetProperties();
           foreach (var classProperty in listOfProperties )
           {
                if (classProperty.Name.EndsWith("_NHBSet"))
                {
                    PropertyInfo myPropInfo = typeof(Customer).GetProperty(classProperty.Name);
                    dynamic Collection =  myPropInfo.GetValue(customer, null);
                    if (Enumerable.FirstOrDefault(Collection) !=null)// Check if collection contains any element
                    {
                       MessageBox.Show("Customer Cannot be deleted");
                       return;
                    }   
                }  
            }
            session.Delete(customer);
            transaction.Commit();
      }
   }
}

La ventaja de este enfoque es que usted no tiene que cambiar su código más tarde si se agregan nuevas colecciones a tu class.And cliente que no es necesario cambiar la consulta SQL como Jaguar suggested. La única cosa que usted debe tener en cuenta es añadir el sufijo particular, a sus colecciones recién añadidos.

scroll top