用C#执行SQL脚本并记录错误

5
我将尝试在C# Windows应用程序中执行一个脚本(.sql文件)到数据库。该SQL文件包含“GO”语句,这意味着我正在使用SMO对象。
我尝试在发生脚本执行错误时继续执行记录任何错误。是否有方法可以实现这一点?
以下是我正在使用的代码:
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
    ServerConnection svrConnection = new ServerConnection(sqlConnection);
    Server server = new Server(svrConnection);

    string script = File.ReadAllText("upgradeDatabase.sql");

    try
    {
        server.ConnectionContext.ExecuteNonQuery(script, ExecutionTypes.ContinueOnError);
     }
     catch (Exception ex)
     {
         //handling and logging for the errors are done here
     }
}

非常感谢您的帮助!

4个回答

4
我认为你有两个问题:
首先,你调用了接受字符串而不是StringCollection的ExecuteNonQuery方法。我想这个方法无法识别用于分隔批处理语句的GO。相反,接受StringCollection的方法ExecuteNonQuery的文档说明可以识别GO。
第二个问题是传递的ExecutionTypes.ContinueOnError。在这种情况下,同一份文档说明如果发生错误,你将无法收到异常。
我认为最好的方法应该是在GO处拆分输入文本,然后构建一个StringCollection传递给ExecuteNonQuery方法,并检查返回的受影响行数数组。 类似这样的代码(需要测试):
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
    ServerConnection svrConnection = new ServerConnection(sqlConnection);
    Server server = new Server(svrConnection);

    string script = File.ReadAllText("upgradeDatabase.sql");
    string[] singleCommand = Regex.Split(script, "^GO", RegexOptions.Multiline);
    StringCollection scl = new StringCollection();
    foreach(string t in singleCommand)
    {
        if(t.Trim().Length > 0) scl.Add(t.Trim());
    }
    try
    {
        int[] result = server.ConnectionContext.ExecuteNonQuery(scl, ExecutionTypes.ContinueOnError);
        // Now check the result array to find any possible errors??
     }
     catch (Exception ex)
     {
         //handling and logging for the errors are done here
     }
}

当然,另一种选择是执行每个单独的语句并删除ContinueOnError标志。然后捕获和记录可能的异常。但这肯定会更慢。

在文本中使用 GO 进行分割可能会破坏脚本。想象一下,你必须从任何地方选择类别。 - Satinder singh
1
你是否注意到我使用了一个正则表达式模式,将GO锚定在行的开头?http://msdn.microsoft.com/zh-cn/library/az24scfc(v=vs.90) - Steve
感谢 Steve 提供的解决方法。我正在执行每一条语句,并捕获任何错误(如果发生)。 - naregkar
你需要一个模式,它能够匹配行中唯一的不区分大小写的语句为GO,并支持可选的GO nnn语法。实际上,GO也是可配置的,有些脚本使用;作为批处理分隔符(别问我为什么...)。例如,请参见https://github.com/rusanu/DbUtilSqlCmd/blob/master/trunk/src/SqlCmd.cs中的`@"^\b*" + BatchDelimiter + @"\b*(\d*)"`。 - Remus Rusanu
@RemusRusanu 我相信你是对的,但如果脚本由使用它的同一人/组织控制/创建,则这可能完全不必要。而且,如果我理解那个“upgradeDatabase.sql”文件名的含义,那么很可能就是这种情况。 - Steve
2
@Steve:没错,但要考虑到后来看到这篇帖子并使用代码却没有考虑“细节”的人。 - Remus Rusanu

1

我不是程序员(数据库管理员),所以我不确定。

我认为以下内容可能有帮助:

svrConnection.FireInfoMessageEventOnUserErrors = true;


1

我非常喜欢这种变体,它使用了InfoMessage事件和处理程序:

        using(SqlConnection sc = new SqlConnection(connStr))
        {
            sc.InfoMessage += new SqlInfoMessageEventHandler(sc_InfoMessage);
            sc.FireInfoMessageEventOnUserErrors = true;
            Server db = new Server(new ServerConnection(sc));
            db.ConnectionContext.ExecuteNonQuery(commandFileText, ExecutionTypes.ContinueOnError); 
        }

您需要添加以下引用:
  • Microsoft.SqlServer.ConnectionInfo.dll
  • Microsoft.SqlServer.Management.Sdk.Sfc.dll
  • Microsoft.SqlServer.Smo.dll
  • Microsoft.SqlServer.SqlEnum.dll

1
这与Andry的答案配合使用。您需要sc.FireInfoMessageEventOnUserErrors = true; - Craig A

0

你可以使用smo库,在这里是如何将其添加到项目中的。

FileInfo file = new FileInfo("upgradeDatabase.sql");
string script = file.OpenText().ReadToEnd();
SqlConnection conn = new SqlConnection(sqlConnectionString);
Server server = new Server(new ServerConnection(conn));
server.ConnectionContext.ExecuteNonQuery(script);

通过你的答案,脚本将在第一个错误处停止执行。我想 OP 是想看到所有的错误。(不是投票者) - David White
嗨@ArsenMkrt,我正在尝试使用您的答案,但在Server server=new..行上出现错误,请问您可以告诉我Server的程序集和命名空间是什么吗?谢谢。 - Umesh Sehta
异常的信息是什么? - Arsen Mkrtchyan
1
可能是因为你的项目中没有引用 smo dll 包而导致出现错误 @Mohit - SRJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接