foreign - Restricciones diferibles en SQL Server
constraint sql server (7)
Aparentemente no.
Encontré alrededor de cinco publicaciones de blog diferentes que dicen que SQLServer (en varias versiones) no admite restricciones diferibles.
Por otro lado, también encontré una publicación que intenta imitar esta característica mediante el uso de "columnas computadas persistentes" (desplazarse a la última entrada), pero caveat emptor
¿Alguna versión de SQL Server admite restricciones diferibles (DC)?
Desde aproximadamente la versión 8.0, Oracle ha soportado restricciones diferibles : restricciones que solo se evalúan cuando se compromete un grupo de instrucciones, no cuando se insertan o actualizan tablas individuales. Las restricciones diferibles difieren de las restricciones de inhabilitación / habilitación, ya que las restricciones siguen activas: se evalúan más adelante (cuando se confirma el lote).
El beneficio de DC es que permiten que las actualizaciones que individualmente serían ilegales se evalúen que, de forma acumulativa, den como resultado un estado final válido. Un ejemplo es crear referencias circulares en una tabla entre dos filas donde cada fila requiere que exista un valor. Ninguna instrucción de inserción individual pasaría la restricción, pero el grupo sí.
Para aclarar mi objetivo, busco portar una implementación de ORM en C # a SQLServer. Desafortunadamente, la implementación se basa en Oracle DC para evitar el cómputo de insertar / actualizar / eliminar pedidos entre filas.
Existe un método para evitar la imposición de restricciones diferidas en ciertas condiciones (a partir de enero de 2017, no hay soporte para restricciones diferidas en SQL Server). Considere el siguiente esquema de base de datos:
Descargo de responsabilidad: la calidad del esquema, o el caso de uso, no está disponible para debate, se ofrece como un ejemplo básico para la solución
CREATE TABLE T (Id TYPE NOT NULL PRIMARY KEY, NextId TYPE NOT NULL);
ALTER TABLE T WITH CHECK ADD CONSTRAINT FK_T2T
FOREIGN KEY (NextId) REFERENCES T (Id);
CREATE UNIQUE NONCLUSTERED INDEX UC_T ON T (NextId);
Donde TYPE es un tipo de datos adecuado para una clave sustituta. La suposición es que el valor de la clave sustituta es asignado por el RDBMS durante la operación INSERT (es decir, IDENTIDAD).
El caso de uso es mantener la "última" versión de la entidad T con NextId = NULL, y almacenar las versiones anteriores manteniendo una lista de un solo enlace T.NextId -> T.Id.
Obviamente, el esquema dado está sujeto al problema de restricción diferida porque la inserción de la nueva "última versión" debe preceder a la actualización de la anterior "última" y durante ese tiempo habrá dos registros en la base de datos con el mismo NextId valor.
Ahora si:
El tipo de datos de la clave primaria no tiene que ser numérico, y puede calcularse de antemano (es decir, UNIQUEIDENTIFIER), luego el problema de la restricción diferida se elude mediante la instrucción MERGE, así:
DECLARE TABLE @MergeTable TABLE (Id UNIQUEIDENTIFIER);
DECLARE @NewLatestVersion UNIQUEIDENTIFIER = NEWID();
INSERT INTO @MergeTable (Id) VALUES (@NewLatestVersion);
INSERT INTO @MergeTable (Id) VALUES (@OldLatestVersion);
MERGE INTO T
USING @MergeTable m ON T.Id = m.Id
WHEN MATCHED THEN UPDATE SET T.NextId = @NewLatestVersion
WHEN NOT MATCHED THEN INSERT (Id) VALUES (@NewLatestVersion);
Aparentemente, la instrucción MERGE completa todas las manipulaciones de datos antes de verificar las restricciones.
Hasta ahora, SQL Server no los admite. ¿Cuál es el problema que estás resolviendo?
OT: En mi humilde opinión hay algunas cosas que SQL Server no admite, pero que tendrían sentido en un entorno empresarial:
- Restricciones diferibles como se menciona aquí
- MARS: ¿Por qué necesitas establecer una opción para algo completamente natural?
- Restricciones de CASCADE DELETE: SQL Server solo permite una única ruta de cascada para una restricción dada CASCADE DELETE. Una vez más, no veo una razón por la cual no se debe permitir la cascada en la eliminación a través de múltiples caminos posibles: al final, en el momento en que realmente se ejecuta, siempre habrá una sola ruta que se usa realmente, entonces ¿por qué? es esta restricción?
- Prevención de transacciones paralelas en una sola conexión ADO.NET.
- Forzar cada comando ejecutado en una conexión que tiene una transacción que se ejecutará dentro de esta transacción.
- Al crear un índice ÚNICO, NULL se trata como si fuera un valor real y se le permite aparecer solo una vez en el índice. La noción de SQL de NULL como un "valor desconocido" indicaría, sin embargo, que los valores NULL se ignoran por completo al crear el índice ...
Todas estas pequeñas cosas hacen que muchas de las características transaccionales e integridad referencial que esperaría de un RDBMS de tamaño completo sean casi inútiles en SQL Server. Por ejemplo, dado que las restricciones diferibles no son compatibles, la noción de una "transacción" como una Unidad de Trabajo externamente consistente es parcialmente negada, la única solución viable -excepto por algunas soluciones sucias- es no definir en absoluto las restricciones de integridad referencial. Yo esperaría que el comportamiento natural de una transacción sea que usted puede trabajar dentro de ella en la forma y el orden de las operaciones que le gustan, y el sistema se asegurará de que sea consistente en el momento en que la cometa. Problemas similares surgen de la restricción de que una restricción de integridad referencial con ON DELETE CASCADE solo se puede definir de forma tal que solo una restricción individual pueda conducir a la eliminación en cascada de un objeto. Esto realmente no se ajusta a la mayoría de los escenarios del mundo real.
Parece que el problema que tienes es que SQL no admite lo que Date y Darwen llaman ''asignación múltiple''. La respuesta estándar de SQL a esto fue ''restricciones diferibles'', que SQL Server no admite. Una restricción SQL Server FK o CHECK se puede marcar con NOCHECK pero no es lo mismo. Para obtener más información, consulte MSDN: ALTER TABLE (Transact-SQL) .
Puedes usar este método
ALTER TABLE your_table NOCHECK CONSTRAINT your_constraint
tu acción
ALTER TABLE your_table WITH CHECK CHECK CONSTRAINT ALL
Si tiene su propia capa ORM, una solución a su problema podría ser separar la actualización del objeto de la actualización de referencia por la lógica de su capa ORM. Su ORM luego trabajaría con transacciones basadas en su cambio del lado del cliente en varios pasos:
- Elimine todas las referencias de clave externa definidas por su conjunto de cambios como eliminadas, es decir, establezca las columnas de clave externa correspondientes en NULO o, para las relaciones que utilizan tablas de asignación, ELIMINEN las entradas de las tablas de asignación, según corresponda.
- Elimine todos los objetos definidos como "eliminados" por sus conjuntos de cambios
- Cree todos los objetos nuevos en su conjunto de cambios, pero aún no establezca las columnas de claves externas
- Actualice todos los cambios de valores "primitivos" en cualquier objeto actualizado en el conjunto de cambios, es decir, no actualice las columnas de claves externas
- Establezca valores de columna clave externa como se define en su conjunto de cambios.
- Agregar asignaciones de tablas de mapeo para mapear relaciones basadas en tablas
- Cometer
Esto debería resolver su problema, ya que todos los objetos a los que se hace referencia existen en cualquier momento que se establece un valor de clave externa ...