Использование "GO" в транзакции

Я создаю веб-приложение, которое пытается установить/обновить базу данных в 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 из Enterprise Library.

но это вызывает исключение с ошибкой при прикладе, несколько ниже

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.

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

Ответ 1

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

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

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

Ответ 2

Я просто хочу добавить, что если вы назовете свою транзакцию, вы можете включить несколько разделов 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

Ответ 3

Бедный человек, чтобы исправить это: разделите 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;
}

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

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

# # # # # BONUS POINTS # # # # # #

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

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

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

Ответ 4

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

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

Ответ 5

проверьте свои скрипты:

  • восстановить резервную копию на резервном сервере
  • запустить сценарии запуска с помощью GO

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

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

Ответ 6

Собственно, вы можете использовать операторы 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

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

Ответ 7

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

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

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

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