问题
Having just built a c# application to run SQL scripts, I've run into a few issues with error handling.
We have a stored procedure in our database which modifies the default constraint for tables (by dropping any existing one and then creating the new one), and it runs fine when we call it from SSMS. However, when we call the same stored procedure from the .Net SqlClient, it gives an error. The error I get in the SqlException
has the message:
System.Data.SqlClient.SqlException: Column already has a DEFAULT bound to it.
Could not create constraint. See previous errors.
This shouldn't happen, since we never see the message in SSMS unless we don't run the drop statement first. If the Drop Constraint
statement is commented out, we see the same message.
Why would the constraint not get dropped when we call the stored procedure from in .Net?
For reference, the relevant code inside the stored procedure is:
SELECT @strSQL = 'ALTER TABLE [' + @strTableName + '] DROP CONSTRAINT [' + @strConstraintName + ']'
EXEC sp_executesql @strSQL
SELECT @strSQL = 'ALTER TABLE [' + @strTableName + '] ADD CONSTRAINT DF_' + @strTableName + '_' + @strColumnName + ' DEFAULT (' + @strDefaultValue + ') FOR ' + @strColumnName
EXEC sp_executesql @strSQL
EDIT: I considered trapping for errors, and ignoring non-fatal errors such as this. However, unfortunately this specific error is a Level 16 error, and errors such as updating a non-existent table are only Level 15. So I can't let this error pass by filtering on the Error Class of the exception.
EDIT 2: Should have mentioned, the @strConstraintName
is determined automatically based on the table name and column name:
SELECT
@strConstraintName = vdc.CONSTRAINT_NAME
FROM
dbo.vw_DEFAULT_CONSTRAINT vdc
WHERE
vdc.TABLE_NAME = @strTableName
AND vdc.COLUMN_NAME = @strColumnName
Resolution
So, it turns out that the vw_DEFAULT_CONSTRAINT that was determining the name of the default constraint was badly written.
It was filtering based on the value of USER_ID() for some reason (the view was written before I started) which wasn't necessary. Removing this restriction from the view returned the correct constraint name.
@ErikE's answer provided a good push in the correct direction. Saving the variable values into a temporary table allowed me to see that the 2 methods weren't actually working the same, which led me to investigate the view further. Kudos to @ErikE for this, which is why I selected his as the correct answer.
I do find it strange though that the value of USER_ID() was not the same, since the connections were identical.
回答1:
If running an SP-statement trace in SQL Profiler doesn't reveal a difference, can you log the @SQL variable contents being executed to a table and review them afterward? I'm really quite confused that they are truly identical.
Is it possible that the drop default constraint is failing due to a name problem? I think you answered this but it would be a plausible answer.
Did you know that dynamic SQL is executed with the permissions of the caller, not the SP owner, unless you take special measures (such as EXECUTE AS
)? Could this be the issue?
Try commenting out the create default from the SP, running it from .Net, and seeing if the default was really dropped by the first statement. Or put a WAITFOR DELAY '5:00'
in between them so you can check mid-run.
回答2:
Try tu use SQL Server Profiler and compare the query from the ADO.NET to your query from the SSMS.
回答3:
Try profiling the execution of the query and extracting the SET
statements the SqlClient
executes on connection. For example this is what I had profiled in the past when debugging performance differences of a query executed by the SqlClient
versus running it in SSMS:
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language us_english
set dateformat mdy
set datefirst 7
set transaction isolation level read committed
Run these SET
statements into SSMS and then try executing your query there again to see if you can replicate the behaviour. Whilst I don't believe this will surface your issue it is at least a good exercise to ensure your session configuration in SSMS is the same as if the query were being executed by the SqlClient
来源:https://stackoverflow.com/questions/9134739/tsql-error-in-net-but-not-in-ssms