2009-06-09 7 views
47

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

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

Объект SqlServices имеет метод «Установить», который принимает 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 транзакции.

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

+0

Посмотрите также на это: [Использование таблицы только после его создания: объект не существует] (http://stackoverflow.com/questions/784953/using-table- just-after-creation-it-object-does-not-exist/785096 # 785096) –

+0

Хорошая точка. Спасибо –

ответ

54

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

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

Вам придется разбить сценарий в партии самостоятельно или использовать что-то вроде sqlcmd с «-с GO »или osql для обработки« GO »

+4

как можно сделать откат? –

+5

SET XACT_ABORT На умных манипуляциях, таких как Red Gate. – gbn

+6

Предыдущий ответ, несмотря на его принятие, выглядит немного неясным для меня.Поэтому я хотел бы добавить соответствующую точность: IMHO абсолютно не проблема с транзакциями транзакций с другими кратными партиями. Таким образом, вы можете отлично поместить «GO» в транзакцию. – AFract

5

EDIT Как указано ниже, я указал tran, где партия была фактически правильной.

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

+9

Не путайте транзакции и партии - инструкции go задают партию команд, которые могут включать одну или несколько транзакций базы данных. –

+0

Это отличная точка. – cmsjr

1

тест сценарии:

  • восстановить резервную копию производства на сервере резервного копирования
  • прогонов запуска сценариев с GOs

установить сценарии:

  • закрыть приложение
  • перейти в однопользовательский режим
  • базы данных резервного копирования
  • Запуск сценариев с ГСН на провал восстановления резервной копии
  • вернуться в многопользовательский
  • приложение рестарт
+1

Понизьте это, если хотите, но вы не получите несколько GO в одной транзакции. Основываясь на ошибке OP, в скрипте есть CREATE, что потребует GO. Этот метод является единственным способом откат, если что-то идет не так. –

+1

Я не понимаю, почему это было приостановлено. Это, безусловно, большая работа, но, похоже, эта идея ударила по этой идее и разрешила откаты (в отличие от некоторых других методов ...) – Beska

+0

Пропущенный b/c он не отвечает на вопрос OP - например, пытается запустить это в пределах приложение. Кроме того, прием приложений в офлайн-режиме настолько уродлив. –

16

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

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

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

# # # # # бонусными баллами # # # # # #

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

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

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

+1

как вы откатите изменения, если в одном разделе скрипта есть ошибка? –

+0

Я планирую использовать одну транзакцию по всем операторам для отката всего процесса. Ура! –

+2

Вышеупомянутые могут неправильно разбивать sql-скрипты, если у вас есть, например, комментарии, содержащие слово GO (за которым следует новая строка) и т. Д. - поэтому используйте внимательно. В качестве альтернативы вы можете использовать что-то вроде следующего: реализация StringReader, которая будет считывать и разбивать SQL и чувствительна к комментариям и т. Д .: https://github.com/DbUp/DbUp/blob/master/src/DbUp /Support/SqlServer/SqlCommandReader.cs – Darrell

-1

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

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

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

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

+1

Это не очень хорошо. Даже простые скрипты, которые просто ALTER VIEW или что-то требуют, находятся в их собственном BATCH. – pilavdzice

+0

Спасибо! Это хорошо знать. Следовательно, отказ от ответственности :) –

+0

Мы используем GO для разделения партий, скажем между drop и create, или для запуска новой партии, где мы используем CREATE/ALTER. удаление GO приведет к другой ошибке CREATE/ALTER должен быть первым оператором в пакете – eka

29

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

Это работает только в SQL Server Management Studio и других подобных инструментах, это неверный SQL, поэтому, например, это не работает на C#. – pilavdzice

+1

Я предполагал, что это будет хранимая процедура. – CodeGrue

1

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

2

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

Declare @ID nvarchar(5); 
set @ID = 5; 
select @ID 
GO 
select @ID 
Смежные вопросы