5

Quiero poder verificar si la eliminación de una fila de una tabla en SQL Server 2008 fracasará debido a una violación de clave externa sin intentar eliminarla.Compruebe si es seguro eliminar una fila

Básicamente, no quiero mostrarle al usuario un botón de borrar si no van a poder eliminarlo porque la clave se usa en otro lado.

Necesito esto en muchos lugares de la aplicación, así que no quiero tener que escribir las comprobaciones manualmente para ver si es seguro eliminar la fila. ¿Alguna sugerencia sobre la mejor manera de lograr esto?

Estoy usando el marco de entidades para acceder a los datos.

Respuesta

2

No hay una manera rápida y fácil de verificar esto. Probablemente puedas construir algo dinámico usando information_schema, pero sin dudas será feo y no muy rápido.

La mejor opción absoluta son las pocas líneas de código personalizado que se necesita para verificar por ubicación.

Otra opción sería iniciar una transacción, intente eliminar. Si falla, entonces lo sabes. Si tiene éxito, revierte la transacción y sabes que la eliminación es posible. Esto sigue siendo feo y está usando transacciones de una manera algo interrumpida, pero funcionaría. Aunque asegúrese de que las eliminaciones en cascada no estén activadas para la tabla.

1

He hecho este tipo de cosas en aplicaciones anteriores. Creé una función llamada algo así como TryDelete(). Dentro del método, intenté eliminar la fila deseada. Si obtuve una excepción FK, la atrapé y devolví falso. En cualquier caso, verdadero o falso, encapsulé la eliminación en una transacción y luego la devolví.

2

Cuando realiza una consulta, realice una UNIÓN IZQUIERDA a la tabla secundaria. Use CanDelete value calculado para decidir si se debe mostrar el botón. El COUNT aquí quitó duplicados si tiene más de 1 fila hijo por fila principal.

SELECT 
    Col1, Col2, Col3, ..., 
    CASE C.Existence WHEN 0 THEN 1 ELSE 0 END AS CanDelete 
FROM 
    ParentTable P 
    LEFT JOIN 
    (
    SELECT COUNT(*) AS Existence, FKColumn 
    FROM Childtable GROUP BY FKColumn 
    ) C ON P.FKColumn = C.FKColumn 
WHERE 
    P.Col = ... 

Otra forma podría ser

SIGN(C.Existence) AS HasChildRows 
+0

¡Excelente idea! Pero, está usando EntityFramework para cargar datos en objetos ... – veljkoz

+0

¿No hay una manera de hacer esto con EF? (Tal vez golpear una vista?) –

+0

@veljkoz, @Jeff Sternal: lo siento, no tengo idea. Podría envolver esto en una vista como se menciona. – gbn

1

Se podría añadir en una clase parcial de su entidad un método que comprobar si existen los objetos referenciados.

Por ejemplo, supongamos que tiene Entity1 que tiene colecciones de Entity2. Básicamente, en cada una de la entidad las clases parciales que le escriba una propiedad IsReferenced eso:

  • Para Entity1 devolver cierto si Entity1 tiene ningún artículo en Entity2
  • Para Entity2 tura de retorno si no hay una referencia a Entity1

Como usted está adivinando, que necesita para asegurarse de que incluye valores de referencia siempre en su búsqueda, o, si está trabajando apegado al contexto, se puede usar en .Load()IsReferenced a buscar las entidades antes de comprobar . Es una sobrecarga, solo depende si está dispuesto a 'pagar' por ello.

Luego, puede mostrar/ocultar el botón 'eliminar' en función de la propiedad del elemento donde sea necesario, evitando tener que repetir las comprobaciones cada vez.

0

Creo que tiene 2 opciones posibles aquí.Como no puede garantizar que todas las relaciones se mapearán en su OM, debería verificarlas en la base de datos.

Usted puede intentar un delting real dentro de una transacción que se deshace después, pero esto también podría funcionar si usted tiene que contraint configurado con eliminaciones en cascada ...

Otra forma sería la extracción de todos contraints de la sysobjects table, y verificar que cada tabla no tenga registros. Pero eso requeriría un poco de SQL dinámico, que también puede ser bastante complicado.

0

Si se encuentra en el nivel de la base de datos me uniría a todas las tablas donde podría existir un conflicto.

los registros que devuelven no se pueden eliminar, lo que significa que el conjunto restante puede ser.

0

Asumiendo que la base de datos es utilizada por múltiples usuarios (que la gran mayoría son) - habrá una oportunidad entre "verificar" que la eliminación es posible y el usuario posiblemente decida eliminar la fila, durante la cual otra persona podría realizar alguna actividad que niegue el resultado de la prueba.

Esto significa que puede mostrar el botón Eliminar, pero en el momento de intentar la eliminación, ya no es posible. Además, es posible que no muestre un botón Eliminar, pero para cuando el usuario haya decidido que quiere eliminar la fila (pero no puede encontrar el botón), se le debe permitir.

No hay forma de evitar este tipo de carreras. Solo dejaría que las personas intenten eliminarlo si así lo desean, pero prepárate para lidiar con las fallas debidas a Foreign Keys.