How can I execute a .sql from C#?

前端 未结 6 591
旧时难觅i
旧时难觅i 2020-12-04 20:05

For some integration tests I want to connect to the database and run a .sql file that has the schema needed for the tests to actually run, including GO statements. How can I

相关标签:
6条回答
  • 2020-12-04 20:46

    Having the same need to automatically run a generated database script from code, I set out to parse the SQL script to remove GO statements and split the script into separate commands (as suggested by @MattBrunell). Removing the GO statements was easy, but splitting the statements on "\r\n" did not work since that screwed up the multiline-statements. Testing a few different approaches, I was quite surprised to find out that the script doesn't have to be split into separate commands at all. I just removed all "GO" statements and sent the whole script (including comments) into SqlCommand:

      using System.Data.SqlClient;
    
      using(SqlConnection connection = new SqlConnection(connectionString))
      using(SqlCommand command = connection.CreateCommand())
      {
        string script = File.ReadAllText("script.sql");
        command.CommandText = script.Replace("GO", "");
        connection.Open();
        int affectedRows = command.ExecuteNonQuery();
      }
    

    This code has been tested with SQL Server 2008 R2 and the script generated by "Database -> Tasks -> Generate Scripts...". Below are some examples of the commands in the script:

    USE [MyDatabase]
    
    ALTER TABLE [MySchema].[MyTable] DROP CONSTRAINT [FK_MyTable_OtherTable]
    DROP TABLE [MySchema].[MyTable]
    
    SET ANSI_NULLS ON
    SET QUOTED_IDENTIFIER ON
    
    /****** Object:  Table [MySchema].[MyTable]    Script Date: 01/23/2013 13:39:29 ******/
    CREATE TABLE [MySchema].[MyTable](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [Subject] [nvarchar](50) NOT NULL,
        [Body] [nvarchar](max) NOT NULL,
     CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    SET IDENTITY_INSERT [MySchema].[MyTable] ON
    INSERT [MySchema].[MyTable] ([Id], [Subject], [Body]) VALUES (1, N'MySubject', N'Line 1
    Line 2
    Line 3
    Multi-line strings are also OK.
    ')
    SET IDENTITY_INSERT [MySchema].[MyTable] OFF
    

    I guess there might be some maximum length for a single SqlCommand, above which the script have to be split. My script, which execute without problems, contains around 1800 statements and is 520 kB.

    0 讨论(0)
  • 2020-12-04 20:48
    using Microsoft.SqlServer.Management.Common;
    using Microsoft.SqlServer.Management.Smo;
    

    You shouldn't need SMO to execute queries. Try using the SqlCommand object instead. Remove these using statements. Use this code to execute the query:

     SqlConnection conn = new SqlConnection(sqlConnectionString);
     SqlCommand cmd = new SqlCommand(script, conn);
     cmd.ExecuteNonQuery();
    

    Also, remove the project reference to SMO. Note: you will want to clean up resources properly.

    Update:

    The ADO.NET libraries do not support the 'GO' keyword. It looks like your options are:

    1. Parse the script. Remove the 'GO' keywords and split the script into separate batches. Execute each batch as its own SqlCommand.
    2. Send the script to SQLCMD in the shell (David Andres's answer).
    3. Use SMO like the code from the blog post.

    Actually, in this case, I think that SMO may be the best option, but you will need to track down why the dll wasn't found.

    0 讨论(0)
  • 2020-12-04 20:49

    You may be interested in this: http://geekswithblogs.net/thomasweller/archive/2009/09/08/automating-database-script-execution.aspx

    It presents a general-purpose 'test fixture' to automatically execute sql-scripts. There is also sample code available, and there are no dependencies to any unusual assemblies whatsoever...

    0 讨论(0)
  • 2020-12-04 21:01

    If you add following references in your project, then original code will work fine.

    I use SQL 2008 Express.

    Path: C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies\

    Files: microsoft.sqlserver.smo.dll, microsoft.sqlserver.connectioninfo.dll and Microsoft.SqlServer.Management.Sdk.Sfc.dll

    0 讨论(0)
  • 2020-12-04 21:07

    MSVCR80 is the Visual C++ 2005 runtime. You may need to install the runtime package. See http://www.microsoft.com/downloads/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647&displaylang=en for more details.

    In addition to resolving the DLL issue and Matt Brunell's answer (which I feel is more appropriate for what you're trying to do), you can use the SQLCMD command line tool (from the SQL Client tools installation) to execute these SQL scripts. Just be sure it's on your path so you don't struggle with path locations.

    This would play out like so:

    Actual command:

    SQLCMD -S myServer -D myDatabase -U myUser -P myPassword -i myfile.sql
    

    Parameters (case matters):

    S: server
    d: database
    U: User name, only necessary if you don't want to use Windows authentication
    P: Password, only necessary if you don't want to use Windows authentication
    i: File to run
    

    Code to execute SQL files:

    var startInfo = new ProcessStartInfo();
    startInfo.FileName = "SQLCMD.EXE";
    startInfo.Arguments = String.Format("-S {0} -d {1}, -U {2} -P {3} -i {4}",
                                        server,
                                        database,
                                        user,
                                        password,
                                        file);
    Process.Start(startInfo);
    

    See http://msdn.microsoft.com/en-us/library/ms162773.aspx for more information on the SQLCMD tool.

    0 讨论(0)
  • 2020-12-04 21:08

    Have you tried running this with a very, very basic script in the .sql file? Maybe something that just inserts one row or creates an arbitrary table? Something that is very easy to verify? Essentially, this code is like hard coding the sql, except you're reading it from a file. If you can get it to work with a very simple file, then I would say that there is likely something wrong with the file structure itself. The post alluded to the fact that there are some stipulations regarding what can and cannot be in the file. If nothing else, it's a good place to start troubleshooting.

    0 讨论(0)
提交回复
热议问题