Я создаю пользовательскую утилиту развертывания дб, я должен считать текстовые файлы, содержащие sql сценарии, и выполнить их против базы данных.
Довольно легкий материал, пока неплохо.
Однако я встретился с препятствием, содержание файла читается успешно и полностью, но когда-то передается в SqlCommand и затем выполняется с SqlCommand. ExecuteNonQuery только часть сценария выполняется.
Я разжег Профилировщика и подтвердил, что мой код не передает весь сценарий.
private void ExecuteScript(string cmd, SqlConnection sqlConn, SqlTransaction trans)
{
SqlCommand sqlCmd = new SqlCommand(cmd, sqlConn, trans);
sqlCmd.CommandType = CommandType.Text;
sqlCmd.CommandTimeout = 9000000; // for testing
sqlCmd.ExecuteNonQuery();
}
// I call it like this, readDMLScript contains 543 lines of T-SQL
string readDMLScript = ReadFile(dmlFile);
ExecuteScript(readDMLScript, sqlConn, trans);
Ага, каждый сталкивается с этой проблемой, когда в первый раз начинает посылать содержимое файлов сценария SQL в базу данных.
GO
не является командой T-SQL. Это маркер конца пакета, распознаваемый всеми интерактивными инструментами SQL Microsoft (Management Studio, isql, osql). Чтобы справиться с этим, вам нужно будет написать свой собственный синтаксический анализатор, чтобы разбивать каждый блок текста в файле между операторами GO
и передавать их в базу данных как отдельные команды.
Как вы реализуете свой синтаксический анализатор, зависит от вас. Это может быть простое (чтение каждой строки за раз, обнаружение строк, состоящих только из GO
и пробелов) или сложное (разметка всех операторов и определение того, является ли GO
подлинное утверждение или фрагмент текста внутри строки или многострочного комментария).
Лично я выбрал первый вариант. Он без проблем обрабатывает 99% всех файлов SQL, с которыми вы, вероятно, когда-либо столкнетесь.Если вы хотите полностью посвятить себя написанию токенизатора, я уверен, что многие люди уже сделали его, просто Google для этого.
Пример:
using(var reader = new SqlBatchReader(new StreamReader(dmlFile))) {
string batch;
while((batch = reader.ReadBatch()) != null) {
var cmd = new SqlCommand(batch, conn, trans) { CommandType = CommandType.Text };
cmd.ExecuteNonQuery();
}
}
class SqlBatchReader : IDisposable {
private TextReader _reader;
public SqlBatchReader(TextReader reader) {
_reader = reader;
}
/// <summary>
/// Return the next command batch in the file, or null if end-of-file reached.
/// </summary>
public string ReadBatch() {
// TODO: Implement your parsing logic here.
}
}
Ответ основан на комментариях под исходным сообщением:
GO - это маркер для Management Studio / osql / isql. Он сообщает, что нужно отправить пакет команд на SQL Server. В вашей утилите вы должны разделить входные данные, используя GO в качестве разделителя, и отправить каждый элемент отдельно (без команды GO)