Использование «GO» в транзакции - PullRequest
52 голосов
/ 09 июня 2009

Я создаю веб-приложение, которое пытается установить / обновить базу данных на App_Start. Часть процедуры установки состоит в том, чтобы убедиться, что в базе данных установлены функции asp.net. Для этого я использую объект System.Web.Management.SqlServices.

Мое намерение состоит в том, чтобы выполнить всю работу с базой данных в рамках транзакции SQL, а в случае неудачи откатить транзакцию и оставить базу данных без изменений.

у объекта SqlServices есть метод "Install", который принимает ConnectionString, но не транзакцию. Поэтому вместо этого я использую SqlServices.GenerateApplicationServicesScripts следующим образом:

string script = SqlServices.GenerateApplicationServicesScripts(true, SqlFeatures.All, _connection.Database);
SqlHelper.ExecuteNonQuery(transaction, CommandType.Text, script, ...);

и затем я использую SqlHelper из библиотеки предприятия.

но это вызывает исключение с множеством ошибок, некоторые из них ниже

Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'.
Incorrect syntax near the keyword 'USE'.
Incorrect syntax near the keyword 'CREATE'.
Incorrect syntax near 'GO'.
The variable name '@cmd' has already been declared. Variable names must be unique within a query batch or stored procedure.

Я предполагаю, что это проблема с использованием оператора GO в транзакции SQL.

Как заставить этот сгенерированный скрипт работать при таком исполнении.

Ответы [ 8 ]

62 голосов
/ 09 июня 2009

GO не является ключевым словом SQL.

Это пакетный разделитель, используемый клиентскими инструментами (например, SSMS) для разбиения всего сценария на пакеты

Вам придется разбить скрипт на пакеты самостоятельно или использовать что-то вроде sqlcmd с "-c GO" или osql для работы с "GO"

36 голосов
/ 20 июня 2012

Я просто хочу добавить, что если вы назовете свою транзакцию, вы можете включить в нее несколько секций GO, и все они будут откатываться как единое целое. Такие как:

BEGIN TRANSACTION TransactionWithGos;
GO

SET XACT_ABORT ON; -- Roll back everything if error occurs in script
GO

-- do stuff
GO

COMMIT TRANSACTION TransactionWithGos;
GO
16 голосов
/ 09 июня 2009

Бедный способ исправить это: разделить SQL на операторы GO. Что-то вроде:

private static List<string> getCommands(string testDataSql)
{
    string[] splitcommands = File.ReadAllText(testDataSql).Split(new string[]{"GO\r\n"}, StringSplitOptions.RemoveEmptyEntries);
    List<string> commandList = new List<string>(splitcommands);
    return commandList;
}

[это было фактически скопировано из приложения, над которым я сейчас работаю. Я, чёрт возьми, этот код]

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

# # # # # БОНУСНЫЕ ТОЧКИ # # # # # #

Способ обработки битов транзакций действительно зависит от операционных целей. По сути, вы можете сделать это двумя способами:

a) Обернуть все выполнение в одну транзакцию, что имеет смысл, если вы действительно хотите, чтобы все выполнялось или не выполнялось (лучший вариант IMHO)

b) Обернуть каждый вызов ExecuteNonQuery() в свою собственную транзакцию. Ну, собственно, каждый вызов - это отдельная транзакция. Но вы можете поймать исключения и перейти к следующему пункту. Конечно, если это типичный сгенерированный материал DDL, часто следующая часть зависит от предыдущей части, поэтому одна из частей, которая будет с ошибкой, вероятно, вызовет весь писк.

5 голосов
/ 09 июня 2009

РЕДАКТИРОВАТЬ , как указано ниже, я указал тран, где партия была действительно правильной.

Проблема не в том, что вы не можете использовать GO в транзакции так часто, как GO указывает на конец пакета и сама не является командой T-SQL. Вы можете выполнить весь сценарий, используя SQLCMD, или разбить его на GO и выполнять каждый пакет по очереди.

4 голосов
/ 14 февраля 2018

GO - это пакетный разделитель в SQL. Это означает завершение одной целой партии. Например, переменная, определенная в одном пакете @ID, не может быть доступна после оператора 'GO'. Пожалуйста, ознакомьтесь с кодом ниже для понимания

Declare @ID nvarchar(5);
set @ID = 5;
select @ID
GO
select @ID
1 голос
/ 17 сентября 2012

На самом деле вы можете использовать операторы GO, когда используете расширения Microsoft.SqlServer.Management.Smo:

    var script = GetScript(databaseName);
    var conn = new SqlConnection(connectionString.ConnectionString);
    var svrConnection = new ServerConnection(conn);
    var server = new Server(svrConnection);
    server.ConnectionContext.ExecuteNonQuery(script);

http://msdn.microsoft.com/de-de/library/microsoft.sqlserver.management.smo.aspx

Все, что вам нужно, это пакеты типов CLR SQL и объекты управления SQL, развернутые из: http://www.microsoft.com/en-us/download/details.aspx?id=29065 (версия SQL 2012)

1 голос
/ 09 июня 2009

протестируйте свои скрипты:

  • восстановление рабочей резервной копии на сервере резервного копирования
  • запускать скрипты запуска с GOs

установите ваши скрипты:

  • закрыть приложение
  • перейти в однопользовательский режим
  • резервная копия базы данных
  • запускать сценарии с GO, при сбое восстанавливать резервную копию
  • вернуться в многопользовательский режим
  • перезапустить приложение
0 голосов
/ 03 ноября 2010

Просто подумал, что я добавлю свое решение здесь ... замените 'GO' на разделитель, который ExecuteNonQuery понимает, т.е. ';' оператор. Используйте эту функцию, чтобы исправить ваш скрипт:

private static string FixGoDelimitedSqlScript(string script)
{
    return script.Replace("\r\nGO\r\n", "\r\n;\r\n");
}

Может не работать для сложного вложенного T-SQL с ';' операторы в них, но сработали у меня и мой сценарий. Я бы использовал метод разделения, указанный выше, но я был ограничен библиотекой, которую использовал, поэтому мне пришлось искать другой обходной путь. Надеюсь, это кому-нибудь поможет!

PS. Я знаю, что ';' operator - это разделитель операторов, а оператор 'GO' - это разделитель пакетов, поэтому, вероятно, любые расширенные сценарии не будут исправлены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...