Ошибка TSQL в .Net, но не в SSMS - PullRequest
       39

Ошибка TSQL в .Net, но не в SSMS

1 голос
/ 04 февраля 2012

Только что построив приложение на c # для запуска сценариев SQL, я столкнулся с несколькими проблемами при обработке ошибок.

У нас есть хранимая процедура в нашей базе данных, которая изменяет ограничение по умолчанию для таблиц (удаляя любую существующую и затем создавая новую), и она работает нормально, когда мы вызываем ее из SSMS. Однако когда мы вызываем ту же хранимую процедуру из .Net SqlClient, она выдает ошибку. Я получаю сообщение об ошибке SqlException:

System.Data.SqlClient.SqlException: Column already has a DEFAULT bound to it.
Could not create constraint. See previous errors.

Этого не должно быть, поскольку мы никогда не увидим сообщение в SSMS, если сначала не выполним оператор drop. Если оператор Drop Constraint закомментирован, мы видим то же сообщение.

Почему ограничение не сбрасывается при вызове хранимой процедуры из .Net?

Для справки, соответствующий код внутри хранимой процедуры:

  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

РЕДАКТИРОВАТЬ: я рассмотрел перехват ошибок и игнорировал нефатальные ошибки, такие как эта. Однако, к сожалению, эта конкретная ошибка является ошибкой уровня 16, а такие ошибки, как обновление несуществующей таблицы, относятся только к уровню 15. Поэтому я не могу допустить, чтобы эта ошибка прошла путем фильтрации по классу ошибок исключения.

РЕДАКТИРОВАТЬ 2: Следует отметить, что @strConstraintName определяется автоматически на основе имени таблицы и имени столбца:

SELECT
        @strConstraintName = vdc.CONSTRAINT_NAME
  FROM
        dbo.vw_DEFAULT_CONSTRAINT vdc
  WHERE
        vdc.TABLE_NAME = @strTableName
        AND vdc.COLUMN_NAME = @strColumnName

Разрешение

Итак, получается, что vw_DEFAULT_CONSTRAINT, который определял имя ограничения по умолчанию, был написан плохо.

По какой-то причине это была фильтрация на основе значения USER_ID () (представление было написано до того, как я начал), в котором не было необходимости. Удаление этого ограничения из представления вернуло правильное имя ограничения.

@ Ответ ErikE обеспечил хороший толчок в правильном направлении. Сохранение значений переменных во временную таблицу позволило мне увидеть, что 2 метода на самом деле не работали одинаково, что побудило меня продолжить изучение представления. Слава @ErikE за это, поэтому я выбрал его в качестве правильного ответа.

Мне кажется странным, что значение USER_ID () не было одинаковым, поскольку соединения были идентичными.

Ответы [ 3 ]

3 голосов
/ 04 февраля 2012

Если при выполнении трассировки SP-оператора в SQL Profiler не обнаружено различий, можете ли вы записать содержимое переменной @SQL в таблицу и просмотреть ее позже? Я очень смущен тем, что они действительно идентичны.

Возможно ли сбой ограничения по умолчанию из-за проблемы с именем? Я думаю, что вы ответили на это, но это был бы правдоподобный ответ.

Знаете ли вы, что динамический SQL выполняется с разрешениями вызывающей стороны, а не владельца SP, если вы не принимаете специальные меры (такие как EXECUTE AS)? Может ли это быть проблемой?

Попробуйте закомментировать создание по умолчанию из SP, запустить его из .Net и посмотреть, действительно ли значение по умолчанию было отброшено первым оператором. Или поместите WAITFOR DELAY '5:00' между ними, чтобы вы могли проверить в середине.

1 голос
/ 04 февраля 2012

Попробуйте профилировать выполнение запроса и извлечь операторы SET, которые SqlClient выполняет при подключении. Например, это то, что я профилировал в прошлом при отладке различий в производительности запроса, выполняемого SqlClient, по сравнению с его выполнением в 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

Запустите эти операторы SET в SSMS, а затем попробуйте выполнить свой запрос еще раз, чтобы посмотреть, сможете ли вы повторить поведение. Хотя я не верю, что это поможет вам решить проблему, по крайней мере, хорошее упражнение - убедиться, что ваша конфигурация сеанса в SSMS такая же, как если бы запрос выполнялся SqlClient

1 голос
/ 04 февраля 2012

Попробуйте использовать SQL Server Profiler и сравните запрос из ADO.NET с вашим запросом из SSMS.

...