我正在构建自定义数据库部署实用程序,我需要读取包含 sql 脚本的文本文件并针对数据库执行它们。
非常简单的东西,到目前为止还不错。
但是我遇到了一个障碍,文件的内容被成功且完整地读取,但是一旦传递到 SqlCommand 然后使用 SqlCommand.ExecuteNonQuery 执行,只有部分脚本被执行。
我启动了 Profiler 并确认我的代码没有通过所有脚本。
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 命令。它是所有 Microsoft 交互式 SQL 工具(Management Studio、isql、osql)都能识别的批处理结束标记。为了处理它,您必须编写自己的解析器来分解 GO
语句之间文件中的每个文本 block ,并将它们作为单独的命令提供给数据库。
如何实现解析器取决于您。它可以是简单的(一次读取每一行,检测只包含 GO
和空格的行)或复杂的(标记所有语句并确定 GO
是一个真正的语句或字符串或多行注释中的一些文本)。
我个人选择了第一个选项。它可以毫不费力地处理您可能遇到的所有 SQL 文件的 99%。如果您想全力以赴编写一个分词器,我相信很多人已经做过了,只需谷歌一下即可。
例子:
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.
}
}
关于c# - SqlCommand() ExecuteNonQuery() 截断命令文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2456552/