GO statements blowing up sql execution in .NET

前端 未结 11 1002
南笙
南笙 2020-12-05 09:48

I have a very simple C# command shell app that executes a sql script generated by SQL Server for scripting schema and data. It\'s blowing up on the \"GO\" statements. Error

相关标签:
11条回答
  • 2020-12-05 10:21

    As mentioned in another answer, GO is not supported.

    You can use String.Split() on your script using your GO statements as delimiters, and run each segment as a command, separately.

    0 讨论(0)
  • 2020-12-05 10:21
    string[] commands = sql.Split( 
        new string[]{"GO\r\n", "GO ", "GO\t"}, StringSplitOptions.RemoveEmptyEntries );
    foreach (string c in commands)
    {
        command = new SqlCommand(c, masterConnection);
        command.ExecuteNonQuery();
    }
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }
    finally
    {
        masterConnection.Close();
    }
    }
    

    Found here. http://blogs.msdn.com/b/onoj/archive/2008/02/26/incorrect-syntax-near-go-sqlcommand-executenonquery.aspx

    0 讨论(0)
  • 2020-12-05 10:22

    There is very nice SqlServerBatchParser class inside FluentMigrator library

    Supports GO GO 3 statements.

    You need to install FluentMigrator.Runner.SqlServer nuget package

    Example generously copied(slightly modified) from FluentMigrator source code:

    using FluentMigrator.Runner.BatchParser;
    using FluentMigrator.Runner.BatchParser.SpecialTokenSearchers;
    using FluentMigrator.Runner.BatchParser.Sources;
    
    void Main()
    {
        var connString = "Server=.;Database=mydb;Trusted_Connection=True;";
        var sql = @"select 1;
    GO
    SELECT 2;
    GO 5";
        ExecuteBatchNonQuery(connString, sql);
    }
    
    public static void ExecuteBatchNonQuery(string ConnectionString, string sql)
    {
        var sqlBatch = string.Empty;
        var conn = new SqlConnection(ConnectionString);
        conn.Open();
    
        try
        {
            var parser = new SqlServerBatchParser();
            parser.SqlText += (sender, args) => { sqlBatch = args.SqlText.Trim(); };
            parser.SpecialToken += (sender, args) =>
            {
                if (string.IsNullOrEmpty(sqlBatch))
                    return;
    
                if (args.Opaque is GoSearcher.GoSearcherParameters goParams)
                {
                    using (var command = conn.CreateCommand())
                    {
                        command.CommandText = sqlBatch;
    
                        for (var i = 0; i != goParams.Count; ++i)
                        {
                            command.ExecuteNonQuery();
                        }
                    }
                }
    
                sqlBatch = null;
            };
    
            using (var source = new TextReaderSource(new StringReader(sql), true))
            {
                parser.Process(source, stripComments: true);
            }
    
            if (!string.IsNullOrEmpty(sqlBatch))
            {
                using (var command = conn.CreateCommand())
                {
                    command.CommandText = sqlBatch;
                    command.ExecuteNonQuery();
                }
            }
        }
        catch (Exception ex)
        {
            using (var message = new StringWriter())
            {
                message.WriteLine("An error occured executing the following sql:");
                message.WriteLine(string.IsNullOrEmpty(sqlBatch) ? sql : sqlBatch);
                message.WriteLine("The error was {0}", ex.Message);
    
                throw new Exception(message.ToString(), ex);
            }
        }
        finally
        {
            conn?.Dispose();
        }
    }
    

    Credits: https://github.com/fluentmigrator/fluentmigrator/blob/v3.2.1/src/FluentMigrator.Runner.SqlServer/Processors/SqlServer/SqlServerProcessor.cs

    0 讨论(0)
  • 2020-12-05 10:24

    GO is not part of SQL, it is something SQL Server Management Studio does for you to split the script up.

    What you need to do is read the query in to a string then split on GO on a line by itself (you may want to use Regex for this)

    //Its better to dispose the SqlCommand, I also switched constructors so I could re-use the SqlCommand.
    using(SqlCommand command = new SqlCommand())
    {
        command.Connection = connection;
    
        var scripts = Regex.Split(script, @"^\w+GO$", RegexOptions.Multiline);
        foreach(var splitScript in scripts)
        {
            command.CommandText = splitScript;
            command.ExecuteNonQuery();
        }
    }
    

    Look at Matt Johnson's answer for a less naive implementation of the GO splitting.

    0 讨论(0)
  • 2020-12-05 10:28

    If you want to be able to use GO you will need to reference to the following dlls

    Microsoft.SqlServer.ConnectionInfo.dll
    Microsoft.SqlServer.Management.Sdk.Sfc.dll
    Microsoft.SqlServer.Smo.dll Microsoft.SqlServer.SqlEnum.dll

    Then execute like so

     using (SqlConnection conn = new SqlConnection(connection))
     {
         Server db = new Server(new ServerConnection(conn));
         string script = File.ReadAllText(scriptPath);
         db.ConnectionContext.ExecuteNonQuery(script);      
     }
    
    0 讨论(0)
提交回复
热议问题