Registros en cascada "eliminados" que realmente no se eliminan

8

Solo trato de obtener algunas ideas sobre lo que la gente hace para este escenario. Tenemos una base de datos del sistema (SQL Server 2008 R2) que tiene tablas y cada tabla tiene un campo que podemos llamar "Eliminado". Básicamente es un campo de bits si es un 1, el registro se elimina, si es un 0, no se elimina. El campo no es anulable y su valor predeterminado es, por supuesto, 0.

No podemos permitir eliminaciones reales en la base de datos, por lo que para evitar esto, establecemos un campo de bits (Eliminado) en verdadero. En nuestra aplicación terminamos con consultas que se ven así:

SELECT blah FROM MyTable WHERE .. AND Deleted=0

Básicamente, filtramos los registros para que solo obtengamos filas no eliminadas. Nuestro problema son los registros relacionados que deben conectarse en cascada. ¿Qué prefiere la gente? ¿Deberíamos hacer esto en el código del lado del servidor para que cuando elimine un registro se elimine (establece el campo de bits eliminado en verdadero) para todos los registros relacionados? ¿O debería ser este un disparador que tiene que verificar este campo y establece el campo de bits para todos los registros relacionados en 1?

¿O estamos completamente en el camino equivocado?

JonH
fuente
use una vista tan eliminada, nunca entre en la imagen, y agrúpese en ese campo de bits
fanático del trinquete
@ratchetfreak: esto no ayuda con los registros relacionados ... ¿cómo manejas la cascada de la eliminación? Imagine una página de empresa que tiene problemas asociados, si alguien elimina la empresa (establece Company.Deleted = 1), ¿cómo elimina los problemas asociados con esa empresa?
JonH
2
Lo único que permitiera automatizar es una actualización de disparo
monstruo de trinquete
1
@ratchetfreak: esa es mi pregunta, ¿deberíamos manejarla a través de un activador de actualización o a través del código del lado del servidor y por qué? Como que sé la respuesta a esto, solo esperaba tener una idea de lo que otros hacen para la eliminación suave: cómo eliminaría las relaciones (la eliminación en cascada lo tiene sin eliminar realmente).
JonH
2
¿Por qué necesita eliminar datos relacionados? Si el padre de los datos relacionados es inaccesible, ¿cómo va a acceder?
Kevin

Respuestas:

2

No hay una buena solución aquí. Las bases de datos ofrecen una eliminación en cascada especial y eficiente a través de claves externas, pero si, como usted dice, la eliminación real no es una opción, entonces no puede aprovechar esa conexión en cascada nativa.

Dependiendo de si las eliminaciones son una ocurrencia común o rara, será más eficiente emular la cascada inmediatamente (a través de consultas o desencadenantes adicionales) cuando se pseudo-elimina algo, o simplemente para buscar todo desde el DB y filtrar la eliminación Bandera en lógica de negocios.

Personalmente, siempre he usado una tercera opción: solo se puede acceder a todos los registros subsidiarios desde el registro maestro, lo que nunca sucede si ese se elimina de forma parcial, ¡por lo que no necesita hacer nada! Obviamente, esto solo funciona si su modelo de datos es un árbol estricto (los comentarios solo se recuperan al ver el producto al que se aplican, los privilegios del usuario solo se recuperan al administrar el usuario al que pertenecen, etc.) en lugar de una web (donde puede consultar todos los comentarios o todos los registros de privilegios indiferentemente), pero creo que esto puede funcionar para sorprendentemente muchos escenarios.

Kilian Foth
fuente
@Killian: creo que esta puede ser la ruta que debemos tomar (disparadores). Sin embargo, como equipo necesitamos discutir esto más con los interesados ​​sobre lo que debería o no en cascada. Gracias por tu increíble aporte.
JonH
5

He hecho esto antes con tablas de auditoría en las que cada cambio en una base de datos se escribe en una tabla espejo de auditoría (Insertar / Actualizar / Eliminar) y los elementos reales reales se eliminan en cascada.

Las tablas espejo son idénticas a la tabla real con la adición de 3 columnas, "ChangeType", "User", "Date".

Esto tiene la doble ventaja de poder eliminar datos correctamente, pero también permite recrear el estado de la base de datos en cualquier momento y documentar el historial completo de cualquier elemento.

Agregaré eso para las eliminaciones en cascada, generalmente prefiero las eliminaciones en cascada en el cliente: el servidor no debería intentar ser demasiado inteligente al respecto, si un usuario elimina una empresa y eso tiene problemas asociados, la acción de eliminar la empresa también debería eliminar cualquier registro correspondiente.

Esto era para un sistema de gestión financiera para un banco de inversión importante, por lo que la auditabilidad era una característica crítica.

Miguel
fuente
Puedo ver esto como una forma y pensamos en ello, pero creo que se ajusta a los sistemas de tipo financiero. Tendríamos que duplicar tantas tablas y relaciones más y la base de código crecería significativamente. Sin embargo, puedo ver la necesidad en su caso.
JonH
Duplicar las tablas no es un problema si las tablas de auditoría se implementan automáticamente y se mantienen sincronizadas, lo mismo que con el código, todo lo que teníamos que hacer era proporcionar un inyector en la capa de datos para cambiar entre las tablas de auditoría y las tablas en vivo, todas las consultas se mantuvo igual.
Michael
Michael, si no te importa que te pregunte qué tan grande era tu equipo de desarrolladores para un proyecto como este.
JonH
Fue hace un tiempo, así que no estoy 100% seguro, pero creo que 4 desarrolladores, 3 probadores y 1 analista.
Michael
1

Hazlo explícitamente en la declaración delete / undelete. También es probable que haya varios escenarios en los que no desee poner en cascada la eliminación.

> Update table1 set deleted=@flag where...
> Update table2 set deleted=@flag where...

Por ejemplo; considere a una persona con varias direcciones.

Eliminando a la persona, simplemente configure Eliminar bandera en persona. No es necesario poner en cascada la eliminación de direcciones, porque cuando restauramos, queremos que esas direcciones vuelvan.

Digamos que la persona se mudó, entonces nos gustaría actualizar el indicador de eliminación solo en la dirección anterior, dejando solo las otras direcciones y la persona. Por lo tanto, la conexión en cascada no siempre es necesaria y dependerá del escenario.

Por lo tanto, creo que debe ser explícito dependiendo de cómo esté configurado su modelo y de lo que esté eliminando.

Jon Raynor
fuente
1
¿No debería mantener la integridad la base de datos (con un desencadenante) en lugar de esperar que el programador de la aplicación esté al tanto de todas las relaciones entre las tablas y en qué necesita conectarse en cascada?
@MichealIT: aquí no hay integridad de datos porque simplemente está actualizando una columna. Está correcto, la actualización podría ir en un disparador, pero definirla explícitamente con una operación de eliminación (SP) facilitaría su búsqueda. En el disparador, uno tendría que interrogar al indicador Eliminar y tomar las medidas apropiadas para determinar si era 1 o 0. La lógica del disparador tiende a ser más oscura en comparación con un procedimiento almacenado.
Jon Raynor
@MichealT: en este ejemplo, a menos que el registro de dirección deba "eliminarse", déjelo en paz. En el sentido de la base de datos relacional, aún mantiene la integridad relacional porque todavía existen todos estos registros. Son las reglas comerciales las que eligen excluirlas. Y sí, un desarrollador comprende mejor cómo se manejan todas estas eliminaciones suaves.
JeffO