Как выполнить файл .SQL script с помощью С#

Я уверен, что на этот вопрос уже был дан ответ, однако я не смог найти ответ, используя инструмент поиска.

С помощью С# я хочу запустить файл .sql. Файл sql содержит несколько операторов sql, некоторые из которых разбиты на несколько строк. Я пробовал читать в файле и пытался выполнить файл с использованием ODP.NET... однако я не думаю, что ExecuteNonQuery действительно предназначен для этого.

Итак, я пробовал использовать sqlplus путем нереста процесса... однако, если я не породил процесс с использованием UseShellExecute, установленным в true, sqlplus зависает и никогда не выйдет. Здесь код, который НЕ РАБОТАЕТ.

Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "sqlplus";
p.StartInfo.Arguments = string.Format("xx/[email protected]{0} @{1}", in_database, s);
p.StartInfo.CreateNoWindow = true;

bool started = p.Start();
p.WaitForExit();

WaitForExit никогда не возвращается... Если я не установил UseShellExecute в true. Побочным эффектом UseShellExecute является то, что вы не можете захватить перенаправленный вывод.

Ответ 1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using System.IO;
using System.Data.SqlClient;

public partial class ExcuteScript : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    string sqlConnectionString = @"Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=ccwebgrity;Data Source=SURAJIT\SQLEXPRESS";

    string script = File.ReadAllText(@"E:\Project Docs\MX462-PD\MX756_ModMappings1.sql");

    SqlConnection conn = new SqlConnection(sqlConnectionString);

    Server server = new Server(new ServerConnection(conn));

    server.ConnectionContext.ExecuteNonQuery(script);
    }
}

Ответ 2

Я пробовал это решение с помощью Microsoft.SqlServer.Management, но он не очень хорошо работал с .NET 4.0, поэтому я написал другое решение, использующее только платформу .NET libs.

  string script = File.ReadAllText(@"E:\someSqlScript.sql");

  // split script on GO command
  IEnumerable<string> commandStrings = Regex.Split(script, @"^\s*GO\s*$", 
                           RegexOptions.Multiline | RegexOptions.IgnoreCase);

  Connection.Open();
  foreach (string commandString in commandStrings)
  {
    if (commandString.Trim() != "")
    {
       using(var command = new SqlCommand(commandString, Connection))
       {
          command.ExecuteNonQuery();
       }
    }
  }     
  Connection.Close();

Ответ 3

Поместите команду для выполнения sql script в пакетный файл, затем выполните приведенный ниже код

string batchFileName = @"c:\batosql.bat";
string sqlFileName = @"c:\MySqlScripts.sql";
Process proc = new Process();
proc.StartInfo.FileName = batchFileName;
proc.StartInfo.Arguments = sqlFileName;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.ErrorDialog = false;
proc.StartInfo.WorkingDirectory = Path.GetDirectoryName(batchFileName);
proc.Start();
proc.WaitForExit();
if ( proc.ExitCode!= 0 )

в пакетном файле напишите что-нибудь вроде этого (образец для SQL-сервера)

osql -E -i %1

Ответ 4

Мне удалось найти ответ, прочитав руководство:)

Эта выдержка из MSDN

Пример кода исключает тупик условие по телефону p.StandardOutput.ReadToEnd перед p.WaitForExit. Условие взаимоблокировки может возникнуть, если вызов родительского процесса p.WaitForExit перед p.StandardOutput.ReadToEnd и дочерний процесс записывает достаточно текста в заполните перенаправленный поток. Родитель процесс будет ждать бесконечно дочерний процесс для выхода. Ребенок процесс будет ждать бесконечно родитель должен читать полностью Поток StandardOutput.

Аналогичная проблема возникает при чтении весь текст из стандартного вывода и стандартные потоки ошибок. Для Например, следующий код С# выполняет операцию чтения на обоих потоков.

Вводит код в это:

Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "sqlplus";
p.StartInfo.Arguments = string.Format("xxx/[email protected]{0} @{1}", in_database, s);

bool started = p.Start();
// important ... read stream input before waiting for exit.
// this avoids deadlock.
string output = p.StandardOutput.ReadToEnd();

p.WaitForExit();

Console.WriteLine(output);

if (p.ExitCode != 0)
{
    Console.WriteLine( string.Format("*** Failed : {0} - {1}",s,p.ExitCode));
    break;
}

Теперь он выйдет правильно.

Ответ 5

Добавлены дополнительные улучшения для ответа surajits:

using System;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using System.IO;
using System.Data.SqlClient;

namespace MyNamespace
{
    public partial class RunSqlScript : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var connectionString = @"your-connection-string";
            var pathToScriptFile = Server.MapPath("~/sql-scripts/") + "sql-script.sql";
            var sqlScript = File.ReadAllText(pathToScriptFile);

            using (var connection = new SqlConnection(connectionString))
            {
                var server = new Server(new ServerConnection(connection));
                server.ConnectionContext.ExecuteNonQuery(sqlScript);
            }
        }
    }
}

Кроме того, мне пришлось добавить следующие ссылки на мой проект:

  • C:\Program Files\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll
  • C:\Program Files\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SqlServer.Smo.dll

Я понятия не имею, нужны ли эти права для dll: s, поскольку в C:\Program Files\Microsoft SQL Server есть несколько папок, но в моем приложении эти две работы.

Ответ 6

Это работает на платформе 4.0 или выше. Поддерживает "GO". Также покажите команду сообщения об ошибке, строке и sql.

using System.Data.SqlClient;

        private bool runSqlScriptFile(string pathStoreProceduresFile, string connectionString)
    {
        try
        {
            string script = File.ReadAllText(pathStoreProceduresFile);

            // split script on GO command
            System.Collections.Generic.IEnumerable<string> commandStrings = Regex.Split(script, @"^\s*GO\s*$",
                                     RegexOptions.Multiline | RegexOptions.IgnoreCase);
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
                foreach (string commandString in commandStrings)
                {
                    if (commandString.Trim() != "")
                    {
                        using (var command = new SqlCommand(commandString, connection))
                        {
                        try
                        {
                            command.ExecuteNonQuery();
                        }
                        catch (SqlException ex)
                        {
                            string spError = commandString.Length > 100 ? commandString.Substring(0, 100) + " ...\n..." : commandString;
                            MessageBox.Show(string.Format("Please check the SqlServer script.\nFile: {0} \nLine: {1} \nError: {2} \nSQL Command: \n{3}", pathStoreProceduresFile, ex.LineNumber, ex.Message, spError), "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            return false;
                        }
                    }
                    }
                }
                connection.Close();
            }
        return true;
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            return false;
        }
    }

Ответ 7

Есть два момента для рассмотрения.

1) Этот исходный код работал у меня:

private static string Execute(string credentials, string scriptDir, string scriptFilename)
{ 
  Process process = new Process();
  process.StartInfo.UseShellExecute = false;
  process.StartInfo.WorkingDirectory = scriptDir;
  process.StartInfo.RedirectStandardOutput = true;
  process.StartInfo.FileName = "sqlplus";
  process.StartInfo.Arguments = string.Format("{0} @{1}", credentials, scriptFilename);
  process.StartInfo.CreateNoWindow = true;

  process.Start();
  string output = process.StandardOutput.ReadToEnd();
  process.WaitForExit();

  return output;
}

Я устанавливаю рабочий каталог в каталог script, так что также работают субскрипты в script.

Назовите его, например. как Execute("usr/[email protected]", "c:\myscripts", "script.sql")

2) Вы должны завершить свой SQL script с помощью инструкции EXIT;

Ответ 8

Это работает для меня:

public void updatedatabase()
{

    SqlConnection conn = new SqlConnection("Data Source=" + txtserver.Text.Trim() + ";Initial Catalog=" + txtdatabase.Text.Trim() + ";User ID=" + txtuserid.Text.Trim() + ";Password=" + txtpwd.Text.Trim() + "");
    try
    {

        conn.Open();

        string script = File.ReadAllText(Server.MapPath("~/Script/DatingDemo.sql"));

        // split script on GO command
        IEnumerable<string> commandStrings = Regex.Split(script, @"^\s*GO\s*$", RegexOptions.Multiline | RegexOptions.IgnoreCase);
        foreach (string commandString in commandStrings)
        {
            if (commandString.Trim() != "")
            {
                new SqlCommand(commandString, conn).ExecuteNonQuery();
            }
        }
        lblmsg.Text = "Database updated successfully.";

    }
    catch (SqlException er)
    {
        lblmsg.Text = er.Message;
        lblmsg.ForeColor = Color.Red;
    }
    finally
    {
        conn.Close();
    }
}