Tengo un problema cuando intento agregar restricciones a mis tablas. Me sale el error:
La introducción de la restricción FOREIGN KEY 'FK74988DB24B3C886' en la tabla 'Empleado' puede causar ciclos o múltiples rutas en cascada. Especifique ON DELETE NO ACTION o ON UPDATE NO ACTION, o modifique otras restricciones de FOREIGN KEY.
Mi restricción es entre una Code
mesa y una employee
mesa. La Code
tabla contiene Id
, Name
, FriendlyName
, Type
y Value
. El employee
tiene un número de campos que los códigos de referencia, por lo que no puede haber una referencia para cada tipo de código.
Necesito que los campos se establezcan como nulos si se elimina el código al que se hace referencia.
¿Alguna idea de cómo puedo hacer esto?
sql
sql-server
constraints
Ricardo Altamirano
fuente
fuente
Respuestas:
SQL Server hace un recuento simple de rutas en cascada y, en lugar de tratar de determinar si realmente existen ciclos, asume lo peor y se niega a crear las acciones referenciales (CASCADE): puede y debe crear las restricciones sin las acciones referenciales. Si no puede alterar su diseño (o hacerlo comprometería las cosas), entonces debería considerar el uso de disparadores como último recurso.
FWIW resolver caminos en cascada es un problema complejo. Otros productos SQL simplemente ignorarán el problema y le permitirán crear ciclos, en cuyo caso será una carrera para ver cuál sobrescribirá el valor en último lugar, probablemente por ignorancia del diseñador (por ejemplo, ACE / Jet hace esto). Entiendo que algunos productos SQL intentarán resolver casos simples. El hecho es que SQL Server ni siquiera lo intenta, lo hace ultra seguro al no permitir más de una ruta y al menos así se lo dice.
Microsoft mismo aconseja el uso de disparadores en lugar de restricciones FK.
fuente
Una situación típica con múltiples rutas en cascada será esta: una tabla maestra con dos detalles, digamos "Maestro" y "Detalle1" y "Detalle2". Ambos detalles son borrados en cascada. Hasta el momento no hay problemas. Pero, ¿qué pasa si ambos detalles tienen una relación de uno a muchos con alguna otra tabla (diga "SomeOtherTable")? SomeOtherTable tiene una columna Detail1ID Y una columna Detail2ID.
En otras palabras: algunos de los registros en SomeOtherTable están vinculados con registros Detail1 y algunos de los registros en SomeOtherTable están vinculados con registros Detail2. Incluso si se garantiza que los registros SomeOtherTable nunca pertenezcan a ambos Detalles, ahora es imposible hacer que la cascada de registros de SomeOhterTable se elimine para ambos detalles, porque hay múltiples rutas en cascada desde Master a SomeOtherTable (una a través de Detail1 y otra a través de Detail2). Ahora puede que ya hayas entendido esto. Aquí hay una posible solución:
Todos los campos de ID son campos clave e incremento automático. El quid se encuentra en los campos DetailMainId de las tablas Detail. Estos campos son clave y referencia referencial. Ahora es posible eliminar todo en cascada eliminando solo los registros maestros. La desventaja es que para cada registro detail1 Y para cada registro detail2, también debe haber un registro DetailMain (que en realidad se crea primero para obtener la identificación correcta y única).
fuente
Señalaría que (funcionalmente) hay una GRAN diferencia entre ciclos y / o múltiples rutas en el ESQUEMA y los DATOS. Si bien los ciclos y quizás las trayectorias múltiples en los DATOS ciertamente podrían complicar el procesamiento y causar problemas de rendimiento (costo de manejo "adecuado"), el costo de estas características en el esquema debería ser cercano a cero.
Dado que la mayoría de los ciclos aparentes en los RDB ocurren en estructuras jerárquicas (organigrama, parte, subparte, etc.) es lamentable que SQL Server asuma lo peor; es decir, ciclo de esquema == ciclo de datos. De hecho, si estás usando restricciones de RI, ¡no puedes construir un ciclo en los datos!
Sospecho que el problema de trayectos múltiples es similar; es decir, múltiples rutas en el esquema no necesariamente implican múltiples rutas en los datos, pero tengo menos experiencia con el problema de múltiples rutas.
Por supuesto, si SQL Server no permite ciclos que aún estaría sujeta a una profundidad de 32, pero eso es probablemente adecuado para la mayoría de los casos. (¡Lástima que no sea una configuración de base de datos, sin embargo!)
Los disparadores "En lugar de Eliminar" tampoco funcionan. La segunda vez que se visita una tabla, se ignora el activador. Entonces, si realmente quieres simular una cascada, tendrás que usar procedimientos almacenados en presencia de ciclos. Sin embargo, el disparador en lugar de eliminar funcionaría para casos de múltiples rutas.
Celko sugiere una "mejor" forma de representar las jerarquías que no introduce ciclos, pero hay compensaciones.
fuente
Hay un artículo disponible en el que se explica cómo realizar múltiples rutas de eliminación mediante disparadores. Quizás esto sea útil para escenarios complejos.
http://www.mssqltips.com/sqlservertip/2733/solving-the-sql-server-multiple-cascade-path-issue-with-a-trigger/
fuente
Según parece, tiene una acción OnDelete / OnUpdate en una de sus claves externas existentes, que modificará su tabla de códigos.
Entonces, al crear esta clave externa, crearía un problema cíclico,
Por ejemplo, actualizar empleados, hace que los códigos cambien por una acción de actualización, hace que los empleados cambien por una acción de actualización ... etc ...
Si publica sus definiciones de tabla para ambas tablas y sus definiciones de clave externa / restricción, deberíamos poder decirle dónde está el problema ...
fuente
Esto se debe a que Emplyee podría tener una Colección de otra entidad, por ejemplo, Calificaciones y Calificación podría tener algunas otras universidades de colección, por ejemplo
}
}
}
En DataContext podría ser como a continuación
}
en este caso hay una cadena de empleados a calificación y de calificación a universidades. Entonces me estaba lanzando la misma excepción.
Funcionó para mí cuando cambié
A
fuente
Trigger es la solución para este problema:
fuente
Este es un error de las políticas de activación de bases de datos de tipo. Un activador es código y puede agregar algunas inteligencias o condiciones a una relación de Cascade como Cascade Deletion. Es posible que deba especializar las opciones de tablas relacionadas alrededor de esto, como desactivar CascadeOnDelete :
O apague esta función por completo:
fuente
Mi solución a este problema encontrado usando ASP.NET Core 2.0 y EF Core 2.0 fue realizar lo siguiente en orden:
Ejecute el
update-database
comando en Package Management Console (PMC) para crear la base de datos (esto da como resultado el error "Introducción de la CLAVE EXTRANJERA ... puede causar ciclos o múltiples rutas en cascada". Error)Ejecute el
script-migration -Idempotent
comando en PMC para crear un script que se pueda ejecutar independientemente de las tablas / restricciones existentesTome la secuencia de comandos resultante y busque
ON DELETE CASCADE
y reemplace conON DELETE NO ACTION
Ejecute el SQL modificado en la base de datos
Ahora, sus migraciones deberían estar actualizadas y las eliminaciones en cascada no deberían ocurrir.
Lástima que no pude encontrar ninguna manera de hacer esto en Entity Framework Core 2.0.
¡Buena suerte!
fuente