Do any versions of SQL Server support deferrable constraints (DC)?
Since about version 8.0, Oracle has supported deferrable constraints - constraints that are only
If you have your own ORM layer, one solution to your problem could be separating object update from reference update by the logic of your ORM layer. Your ORM would then work with transactions based on your client-side change set in several steps:
This should solve your problem, since all objects referenced exist at any time a foreign key value is set...
OT: There are IMHO quite a few things SQL Server does not support, but would make sense in an enterprise environment:
All these little things make many of the referential integrity and transactional features you would expect from a full-sized RDBMS nearly useless in SQL Server. For example, since deferrable constraints are not supported, the notion of a "transaction" as an externally consistent Unit Of Work is partly negated, the only viable solution - except fro some dirty workarounds - being to not define referential integrity constraints at all. I would expect, the natural behavior of a transaction be that you can work inside it in the way and order of operations you like, and the system will make sure it is consistent at the time you commit it. Similar problems arise from the restriction, that a referential integrity constraint with ON DELETE CASCADE may only be defined in a way that only one single constraint can lead to the cascaded deletion of an object. This really doesn't fit most real-world scenarios.
There's a method to work around the missing deferred constraint enforcement under certain conditions (as of January 2017, there's no support for deferred constraints in SQL Server). Consider the following database schema:
Disclaimer: The quality of the schema, or the use case, is not up for a debate here, it is given as a basic example for the workaround
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);
Where TYPE is some suitable data type for a surrogate key. The assumption is that the value for the surrogate key is assigned by the RDBMS during the INSERT operation (i.e. IDENTITY).
The use case is to keep the "latest" version of the entity T with NextId = NULL, and store the previous versions by maintaining a single-linked list T.NextId -> T.Id.
Obviously, the given schema is subject to the deferred constraint problem because the insert of the new-"latest" version must precede the update of the old-"latest" and during that time there will be two records in the database with the same NextId value.
Now, if:
The data type of the primary key doesn't have to be numeric, and can be calculated in advance (i.e. UNIQUEIDENTIFIER), then the deferred constraint problem is sidestepped using MERGE statement, like so:
DECLARE @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);
Apparently, MERGE statement completes all data manipulations before checking the constraints.
It sounds like the problem you have is that SQL does not support what Date and Darwen call 'multiple assignment'. Standard SQL's response to this was 'deferrable constraints', which SQL Server does not support. A SQL Server FK or CHECK constraint can be flagged with NOCHECK but its not quite the same. For more details see MSDN: ALTER TABLE (Transact-SQL).
Apparently not.
I found about five different blog posts all saying SQLServer (in various versions) does not support Deferrable Constraints.
On the other hand, I also found a post which attempts to mimic this feature by using "persisted computed columns," (scroll to the last entry), but caveat emptor
You can use this method
ALTER TABLE your_table NOCHECK CONSTRAINT your_constraint
your action
ALTER TABLE your_table WITH CHECK CHECK CONSTRAINT ALL