代码之家  ›  专栏  ›  技术社区  ›  Pablo Fernandez

如何从C_执行.sql?

  •  15
  • Pablo Fernandez  · 技术社区  · 15 年前

    对于某些集成测试,我希望连接到数据库并运行一个.sql文件,该文件具有实际运行测试所需的架构,包括go语句。如何执行.sql文件?(或者这是完全错误的做法?)

    我找到了 a post in the MSDN forum 显示此代码:

    using System.Data.SqlClient;
    using System.IO;
    using Microsoft.SqlServer.Management.Common;
    using Microsoft.SqlServer.Management.Smo;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string sqlConnectionString = "Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=True";
                FileInfo file = new FileInfo("C:\\myscript.sql");
                string script = file.OpenText().ReadToEnd();
                SqlConnection conn = new SqlConnection(sqlConnectionString);
                Server server = new Server(new ServerConnection(conn));
                server.ConnectionContext.ExecuteNonQuery(script);
            }
        }
    }
    

    但在最后一行,我得到了这个错误:

    System.Reflection.Target调用异常: 异常已由引发 调用的目标。---gt; System.TypeInitializationException(系统类型初始化异常): “”的类型初始值设定项 引发异常。---gt; .模块例外: C++模块在加载期间失败 AppDomain初始化。---gt; System.dllNotFoundException:无法 加载dll“msvcr80.dll”:指定的 找不到模块。(例外) 来自hresult:0x8007007e)。

    我被告知从某个地方去下载那个DLL,但这听起来很糟糕。有更干净的方法吗?还有别的办法吗?我做错什么了?

    我使用的是Visual Studio 2008、SQL Server 2008、.NET 3.5SP1和C 3.0。

    6 回复  |  直到 10 年前
        1
  •  29
  •   Matt Brunell    15 年前
    using Microsoft.SqlServer.Management.Common;
    using Microsoft.SqlServer.Management.Smo;
    

    您不应该需要SMO来执行查询。尝试改用sqlcommand对象。删除这些using语句。使用此代码执行查询:

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

    另外,删除对SMO的项目引用。注意:您需要正确清理资源。

    更新:

    ADO.NET库 do not support the 'GO' keyword . 您的选择如下:

    1. 分析脚本。删除“go”关键字并将脚本拆分为单独的批。将每个批作为自己的sqlcommand执行。
    2. 将脚本发送到shell中的sqlcmd(DavidAndres的答案)。
    3. 使用类似于博客文章中的代码的SMO。

    实际上,在这种情况下,我认为SMO可能是最好的选择,但是您需要找出没有找到DLL的原因。

        2
  •  9
  •   David Andres    15 年前

    MSVCR80是Visual C++ 2005运行时。您可能需要安装运行时包。参见 http://www.microsoft.com/downloads/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647&displaylang=en 了解更多详细信息。

    除了解决dll问题和Matt Brunell的答案(我认为这更适合您尝试做的事情),您还可以使用sqlcmd命令行工具(从SQL客户端工具安装)来执行这些SQL脚本。只需确保它在您的路径上,这样您就不会与路径位置发生冲突。

    这样就可以了:

    实际命令:

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

    参数(案例事项):

    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
    

    执行SQL文件的代码:

    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);
    

    http://msdn.microsoft.com/en-us/library/ms162773.aspx 有关sqlcmd工具的详细信息。

        3
  •  2
  •   Anlo    11 年前

    由于同样需要从代码中自动运行生成的数据库脚本,我开始分析SQL脚本以删除go语句,并将脚本拆分为单独的命令(如@mattbrunell建议的那样)。删除go语句很容易,但是在上拆分语句 "\r\n" 因为那把多行语句搞砸了,所以没用。测试了几种不同的方法,我很惊讶地发现脚本根本不需要拆分成单独的命令。我刚刚删除了所有“go”语句,并将整个脚本(包括注释)发送到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();
      }
    

    此代码已通过SQL Server 2008 R2和“数据库->任务->生成脚本…”生成的脚本进行了测试。下面是脚本中的一些命令示例:

    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
    

    我想单个sqlcommand可能有一些最大长度,在这个长度之上脚本必须被拆分。我的脚本执行无问题,包含大约1800条语句,大小为520 KB。

        4
  •  0
  •   Chris Thompson    15 年前

    您是否尝试在.sql文件中使用非常基本的脚本来运行它?可能只是插入一行或创建一个任意表?很容易验证的东西?本质上,这段代码就像是对SQL进行硬编码,只是从文件中读取它。如果您能让它处理一个非常简单的文件,那么我会说文件结构本身可能有问题。这篇文章提到了这样一个事实,即关于档案中可以和不能有什么规定。如果没有别的,这是开始故障排除的好地方。

        5
  •  0
  •   Thomas Weller    15 年前

    您可能对此感兴趣: http://geekswithblogs.net/thomasweller/archive/2009/09/08/automating-database-script-execution.aspx

    它提供了一个通用的“测试夹具”来自动执行SQL脚本。还有可用的示例代码,并且不依赖于任何异常的程序集…

        6
  •  0
  •   Miguel    14 年前

    如果在项目中添加以下引用,则原始代码可以正常工作。

    我使用SQL 2008 Express。

    路径: C:\程序文件(x86)\Microsoft SQL Server\100\sdk\assembly\

    文件夹: Microsoft.sqlserver.smo.dll、Microsoft.sqlserver.connectioninfo.dll和Microsoft.sqlserver.management.sdk.sfc.dll