Change FK with check when using @disable_constraints
vminds opened this issue · comments
Not sure if this is concerned an issue, or known by design. When requesting to disable the FK constraints (@disable_constraints param set to 1) it changes the with check option to with nocheck (so it will no longer validate the existing data integrity).
To be clear generate-sql-merge instructs:
ALTER TABLE dbo.Table1 NOCHECK CONSTRAINT ALL
ALTER TABLE dbo.Table1 CHECK CONSTRAINT ALL
For example:
-- original
ALTER TABLE dbo.Table1 WITH CHECK ADD CONSTRAINT [FK_Table1_Table2] FOREIGN KEY([tbl2Id])
REFERENCES dbo.Table2 ([Id])
GO
ALTER TABLE dbo.Table1 CHECK CONSTRAINT [FK_Table1_Table2]
GO
-- after executing ALTER TABLE dbo.Table1 NOCHECK CONSTRAINT ALL
ALTER TABLE dbo.Table1 WITH NOCHECK ADD CONSTRAINT [FK_Table1_Table2] FOREIGN KEY([tbl2Id])
REFERENCES dbo.Table2 ([Id])
GO
ALTER TABLE dbo.Table1 NOCHECK CONSTRAINT [FK_Table1_Table2]
GO
-- after executing ALTER TABLE dbo.Table1 CHECK CONSTRAINT ALL
ALTER TABLE dbo.Table1 WITH NOCHECK ADD CONSTRAINT [FK_Table1_Table2] FOREIGN KEY([tbl2Id])
REFERENCES dbo.Table2 ([Id])
GO
ALTER TABLE dbo.Table1 CHECK CONSTRAINT [FK_Table1_Table2]
GO
-- after executing ALTER TABLE dbo.Table1 WITH CHECK CHECK CONSTRAINT ALL
ALTER TABLE dbo.Table1 WITH CHECK ADD CONSTRAINT [FK_Table1_Table2] FOREIGN KEY([tbl2Id])
REFERENCES dbo.Table2 ([Id])
GO
ALTER TABLE dbo.Table1 CHECK CONSTRAINT [FK_Table1_Table2]
GO
That's interesting. So, in this example, the state of the table is changed by simply neglecting to perform a check of the data upon re-enabling the constraint.
For background, @disable_constraints
is one of the parameters that was inherited from the original project, sp_generate_inserts
, so I can't be exactly sure what the intent behind this behaviour was.
As a developer, this seems like a bug: the state of the table structure ought not be changed by a tool that is focused on data movement. If it needs to temporarily modify the table in order to achieve its aim, then that's fine, but it should change it back to the way it was (whether that state was WITH CHECK
or WITH NOCHECK
) once the operation is complete.
@readyroll This only works as expected if the table definition prior merge is specifying the "WITH CHECK" instruction, but not when "WITH NOCHECK". Chances are the original table definition is defined using "WITH NOCHECK" hence the merge script will alter its DDL. I guess you need to save that somehow into a variable so you can reuse it when done. I can have a closer look if you like, let me know.
@vminds Must admit I got a bit lazy with this one upon coming to the same realization as you, with respect to the need to capture the state of the "Check existing data on creation" property at runtime. The difficulty there is that the generated statements (i.e. ALTER TABLE [Table] NOCHECK CONSTRAINT; MERGE...; ALTER TABLE [Table] CHECK CONSTRAINT
) are currently performed in separate batches. I'd prefer to avoid using temp tables if at all possible, so if you can think of a way that avoids that it would be great to hear.
The alternative solution would be to try and source the state of the property at design time (i.e. when the MERGE
is generated), which would get around that particular problem but won't take into account different states in other target db environments. For my use cases, that would be an acceptable compromise but would be keen to hear your thoughts.
@readyroll I understand the complexity to address this in the current design. For me this is not a blocking problem btw, but decided to report it anyway. I believe we should not merge the branch to main though, as it does not fix the issue. Thanks.