2009-06-15 7 views
32

Des versions de SQL Server prennent-elles en charge les contraintes différentielles (DC)? Depuis la version 8.0, Oracle has supported deferrable constraints - contraintes qui sont évaluées uniquement lorsque vous validez un groupe d'instructions, et non lorsque vous insérez ou mettez à jour des tables individuelles. Les contraintes reportables diffèrent des seules contraintes de désactivation/activation, en ce sens que les contraintes sont toujours actives - elles sont simplement évaluées plus tard (lorsque le lot est validé).Contraintes déportables dans SQL Server

L'avantage de DC est de permettre l'évaluation de mises à jour qui, individuellement, seraient illégales et aboutiraient de manière cumulative à un état final valide. Un exemple est la création de références circulaires dans une table entre deux lignes où chaque ligne nécessite une valeur pour exister. Aucune instruction d'insertion individuelle ne passerait la contrainte - mais le groupe peut le faire. Pour clarifier mon objectif, je cherche à porter une implémentation ORM en C# vers SQLServer - malheureusement l'implémentation repose sur Oracle DC pour éviter de calculer les ordres d'insertion/mise à jour/suppression parmi les lignes.

+0

Demandez-vous essentiellement une variante de [cette question] (http://stackoverflow.com/questions/998267/deferred-constraint-checking)? –

Répondre

9

Jusqu'à présent, SQL Server ne les prend pas en charge. Quel est le problème que vous résolvez?

+0

Nous avons une couche ORM dans notre système d'entreprise qui tire parti de DC dans Oracle que nous voulons porter sur SQL Server. Malheureusement, DC ne semble pas être soutenu ce qui complique l'effort de portage de la mise en œuvre. En particulier, le réseau d'enregistrements de changements devra être traité dans un ordre très particulier (et difficile à calculer) pour éviter de violer les contraintes RI. Je cherche juste un moyen d'éviter de faire ça. – LBushkin

+2

J'ai écrit un petit article à ce sujet il y a quelque temps. Fondamentalement, vous sauvegardez les lignes de brouillon dans toutes vos tables, que vous les marquez comme terminées, à quel point RI s'allume. Google "Imiter les contraintes reportables avec des colonnes calculées persistantes." –

3

Apparemment non.

J'ai trouvé environ cinq articles de blog différents disant que SQLServer (dans diverses versions) ne supporte pas les contraintes reportables.

D'autre part, j'ai aussi trouvé un poste qui tente d'imiter cette fonctionnalité en utilisant "persisted computed columns," (faites défiler jusqu'à la dernière entrée), mais caveat emptor

+1

le lien semble être rompu? –

3

Il semble que le problème que vous avez est que SQL ne supporte pas ce que Date et Darwen appellent 'assignation multiple'. La réponse standard de SQL à ceci était des 'contraintes reportables', que SQL Server ne supporte pas. Une contrainte SQL Server FK ou CHECK peut être marquée avec NOCHECK mais ce n'est pas tout à fait la même chose. Pour plus de détails, voir MSDN: ALTER TABLE (Transact-SQL).

21

OT: Il y a à mon humble avis pas mal de choses SQL Server ne prend pas en charge, mais aurait du sens dans un environnement d'entreprise:

  • contraintes reportables mentionnées ici
  • MARS: Juste pourquoi vous devez définir une option pour quelque chose de complètement naturel?
  • Contraintes CASCADE DELETE: SQL Server n'autorise qu'un seul chemin de cascade pour une contrainte CASCADE DELETE donnée. Encore une fois, je ne vois pas de raison pour laquelle il ne devrait pas être possible de cascade sur la suppression par plusieurs chemins possibles: Au final, au moment où il est vraiment exécuté, il y aura toujours un seul chemin réellement utilisé, alors pourquoi est cette restriction?
  • Prévention des transactions parallèles sur une seule connexion ADO.NET.
  • Forçage de chaque commande exécutée sur une connexion qui a une transaction à exécuter dans cette transaction.
  • Lors de la création d'un index UNIQUE, NULL est traité comme s'il s'agissait d'une valeur réelle et ne peut apparaître qu'une seule fois dans l'index. La notion de SQL NULL comme une « valeur inconnue », indiquent toutefois que, que les valeurs NULL être totalement ignoré lors de la création de l'indice ...

Toutes ces petites choses font beaucoup de l'intégrité référentielle et fonctionnalités transactionnelles vous le feriez attendre d'un SGBDR de taille complète presque inutile dans SQL Server.Par exemple, puisque les contraintes reportables ne sont pas supportées, la notion de «transaction» comme unité de travail externe est partiellement annulée, la seule solution viable - sauf quelques solutions de contournement sales - étant de ne pas du tout définir les contraintes d'intégrité référentielle. Je m'attendrais, le comportement naturel d'une transaction soit que vous pouvez travailler à l'intérieur de la façon et l'ordre des opérations que vous aimez, et le système s'assurera qu'il est cohérent au moment où vous l'engagez. Des problèmes similaires découlent de la restriction, à savoir qu'une contrainte d'intégrité référentielle avec ON DELETE CASCADE ne peut être définie que d'une manière telle qu'une seule contrainte peut entraîner la suppression en cascade d'un objet. Cela ne correspond pas vraiment à la plupart des scénarios du monde réel.

+2

Vous pouvez maintenant avoir des index uniques contenant des valeurs null en utilisant un index filtré. – LMK

1

Si vous avez votre propre couche ORM, une solution à votre problème pourrait être de séparer la mise à jour d'objet de la mise à jour de référence par la logique de votre couche ORM. Votre ORM travaillerait ensuite avec des transactions en fonction de votre changement côté client établi en plusieurs étapes:

  1. supprimer toutes les références clés étrangères définies par votre changement défini comme étant supprimé, ce jeu correspondant colonnes de clé étrangère à NULL, ou , pour les relations utilisant des tables de mappage, SUPPRIMER les entrées des tables de mappage selon les besoins.
  2. Supprimer tous les objets définis comme « supprimé » par votre changement définit
  3. Créer tous les nouveaux objets dans votre jeu de changement, mais ne définissez pas encore colonnes de clé étrangère
  4. Mise à jour toutes les modifications de valeur « primitives » sur tous les objets mis à jour à l'ensemble de modifications, c.-à-d. ne pas mettre à jour les colonnes de clé étrangère
  5. Définissez les valeurs de colonne de clé étrangère telles que définies dans votre ensemble de modifications.
  6. applications de table de mappage Ajouter des pour les relations à base de table de mappage
  7. COMMIT

Cela devrait résoudre votre problème, puisque tous les objets référencés existent à tout moment une valeur clé étrangère est définie ...

+0

Ou utilisez une procédure stockée et branchez-la dans Insert() Update() de cette entité dans l'ORM (Entity Framework et Linq to SQL permet cela http://stackoverflow.com/questions/5346601/stored-procedures-and- orms) –

1

Il existe une méthode pour contourner l'application de contrainte différée manquante sous certaines conditions (à compter de janvier 2017, il n'existe aucun support pour les contraintes différées dans SQL Server). Considérez le schéma de base de données suivante:

Avertissement: La qualité du schéma, ou le cas d'utilisation, est pas pour un débat ici, il est donné comme un exemple de base pour la solution de contournement

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); 

Où TYPE est un type de données approprié pour une clé de substitution. L'hypothèse est que la valeur de la clé de substitution est attribuée par le SGBDR au cours de l'opération INSERT (c'est-à-dire IDENTITY).

Le cas d'utilisation est de conserver la "dernière" version de l'entité T avec NextId = NULL, et de stocker les versions précédentes en maintenant une liste à un seul lien T.NextId -> T.Id. De toute évidence, le schéma donné est soumis au problème de contrainte différée car l'insertion de la nouvelle version "dernière" doit précéder la mise à jour de l'ancienne "dernière" et pendant ce temps, il y aura deux enregistrements dans la base de données. avec la même valeur NextId.

Maintenant, si:

Le type de données de la clé primaire ne doit pas être numérique, et peut être calculé à l'avance (à savoirUNIQUEIDENTIFIER), le problème de contrainte différée est contournée en utilisant MERGE, comme ceci:

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); 

Apparemment, MERGE complète toutes les manipulations de données avant de vérifier les contraintes.

Questions connexes