ADO.NET и ExecuteNonQuery:как использовать DDL
-
29-09-2019 - |
Вопрос
Я выполняю SQL-скрипты для изменения схемы базы данных.Выглядит это примерно так:
using (var command = connection.CreateCommand())
{
command.CommandText = script;
command.ExecuteNonQuery();
}
Кроме того, команды выполняются в рамках транзакции.
Сумма выглядит примерно так:
Alter Table [TableName]
ADD [NewColumn] bigint NULL
Update [TableName]
SET [NewColumn] = (SELECT somevalue FROM anothertable)
Я получаю сообщение об ошибке, потому что NewColumn
не существует.Кажется, он анализирует и проверяет его перед выполнением.
Когда я выполняю весь процесс в Management Studio, я могу поместить GO
между утверждениями, тогда это работает.Когда я кладу GO
в скрипт, ADO.NET жалуется (неправильный синтаксис рядом с 'GO').
Я мог бы разделить скрипт на отдельные скрипты и выполнить его отдельными командами, с этим было бы трудно справиться.Я мог бы разделить это на каждый GO
, разбираю скрипт сам.Я просто думаю, что должно быть лучшее решение и что я чего-то не понял.Как должны выполняться подобные скрипты?
Моя реализация, если кого-то заинтересует, согласно ответу Джона Сондерса:
List<string> lines = new List<string>();
while (!textStreamReader.EndOfStream)
{
string line = textStreamReader.ReadLine();
if (line.Trim().ToLower() == "go" || textStreamReader.EndOfStream)
{
ExecuteCommand(
string.Join(Environment.NewLine, lines.ToArray()));
lines.Clear();
}
else
{
lines.Add(line);
}
}
Решение
Вы должны запустить каждую партию отдельно. В частности, для запуска скрипта, который может содержать несколько партий («Go» ключевых слов), вы должны разделить скрипт на ключевые слова «GO».
Не испытано:
string script = File.ReadAllText("script.sql");
string[] batches = script.Split(new [] {"GO"+Environment.NewLine}, StringSplitOptions.None);
foreach (string batch in batches)
{
// run ExecuteNonQuery on the batch
}
Другие советы
Не используете для этого одну из многочисленных библиотек ORM?Хорошо :-)
Чтобы быть в полной безопасности при запуске скриптов, которые вносят структурные изменения, используйте SMO, а не SqlClient, и убедитесь, что MARS не включен через строку подключения (SMO обычно жалуется, если это так или иначе).Ищите Подключение к серверу class и ExecuteNonQuery - разные библиотеки DLL, конечно :-)
Разница в том, что SMO dll передает скрипт как есть в SQL, так что это подлинный эквивалент запуска его в SSMS или через строку isql cmd.Нарезка на GO-s заканчивается гораздо большим сканированием каждый раз, когда вы сталкиваетесь с очередным сбоем (например, GO может быть в середине многострочного комментария, может быть несколько инструкций USE, скрипт может удалять саму базу данных, к которой подключен SqlClient - упс :-).Я только что уничтожил одну такую вещь в унаследованной мной кодовой базе (после того, как более сложные скрипты вступили в конфликт с MARS, а MARS хорош для производственного кода, но не для администрирования).