【问题标题】:How can I execute a .sql from C#?如何从 C# 执行 .sql?
【发布时间】:2014-07-04 20:42:14
【问题描述】:

对于一些集成测试,我想连接到数据库并运行一个 .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.TargetInvocationException: 异常已被 调用的目标。 ---> System.TypeInitializationException: '' 的类型初始化器 抛出异常。 ---> .ModuleLoadException: C++ 模块加载失败 应用域初始化。 ---> System.DllNotFoundException:无法 加载 DLL 'MSVCR80.dll':指定 找不到模块。 (例外 来自 HRESULT:0x8007007E)。

有人告诉我从某个地方下载那个 DLL,但这听起来很 hacky。有更清洁的方法吗?还有另一种方法吗?我做错了什么?

我正在使用 Visual Studio 2008、SQL Server 2008、.Net 3.5SP1 和 C# 3.0 进行此操作。

【问题讨论】:

    标签: c# sql sql-server sql-server-2008


    【解决方案1】:
    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(David Andres 的回答)。
    3. 像博客文章中的代码一样使用 SMO。

    实际上,在这种情况下,我认为 SMO 可能是最好的选择,但您需要追查为什么找不到 dll。

    【讨论】:

    • 马特,相当扎实。在我现在正在进行的一个项目中,我们的代码使用 Smo 的方式与 OP 中描述的方式完全相同。我不明白为什么 SqlCommand 更合适不是很明显......直到我读到你的答案。
    • 如果 SQL 文件包含“GO”语句,这是否有效?我的理解是它没有。
    • 我还没有测试过。我相信确实如此。
    • 它没有。从 SQL Server 导出的架构中有很多东西在这种方法下失败:测试方法 IsItScienceFiction.Tests.UserTest.TestMethod1 抛出异常:System.Data.SqlClient.SqlException:'GO' 附近的语法不正确。关键字“SET”附近的语法不正确。关键字“ALTER”附近的语法不正确。
    • GO 不是 SQL 命令。 GO 是 SQL Server 存储过程中使用的关键字,它告诉服务器执行您给它的 SQL。使用 SQLCommand 执行 SQL 时不需要“GO”;你只需要 Execute() 它。
    【解决方案2】:

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

    有关 SQLCMD 工具的更多信息,请参阅http://msdn.microsoft.com/en-us/library/ms162773.aspx

    【讨论】:

    • 有没有办法运行sql文件而不需要安装旧的Visual C++的运行时?
    • @DavidAndres 我需要使用什么文件,我认为这是我的 .mdf 文件吧
    • @Anjali:有问题的文件是一个 SQL 文件。
    • @DavidAndres : -i 文件参数,可以包含空格吗?
    • @Tony_KiloPapaMikeGolf:不像上面使用的那样,但我怀疑将文件名用双引号括起来会很好。
    【解决方案3】:

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

    【讨论】:

    • 您是否可以简单地删除所有“GO”取决于您的脚本中的内容。某些语句,例如 CREATE PROCEDURE,必须是批处理中的第一个语句(即它们必须是单独的,或者前面有一个“GO”)。
    • 这可能不是一个很好的解决方案。脚本中“GO”的原因是如果“GO”之前的部分失败,人们希望脚本的其余部分继续执行。剥离 GO 意味着您的脚本将无法按照编写者的预期运行。
    • 答案不正确!仅仅删除“GO”是不够的。您必须将您的脚本分成多个批次并分别执行。因为这就是 GO 命令的用途。否则,正如 Rory MacLeod 所说,您可能会遇到问题。
    【解决方案4】:

    您是否尝试过在 .sql 文件中使用非常非常基本的脚本来运行它?也许只是插入一行或创建任意表的东西?很容易验证的东西?从本质上讲,这段代码就像对 sql 进行硬编码,只是您是从文件中读取它。如果您可以让它与一个非常简单的文件一起工作,那么我会说文件结构本身可能有问题。该帖子暗示了一个事实,即关于文件中可以和不可以的内容有一些规定。如果不出意外,这是开始故障排除的好地方。

    【讨论】:

    • 该文件是从 SQL Server 本身导出的,没有手动生成,所以它应该是有效的。帖子说如果文件有 go 语句,这是运行它的唯一方法,这就是我这样做的原因。我用 select(1 + 1) 替换了文件的内容,我得到了完全相同的错误。我认为这不是 SQL 错误。
    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

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

      我使用 SQL 2008 Express。

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

      文件: microsoft.sqlserver.smo.dll、microsoft.sqlserver.connectioninfo.dll 和 Microsoft.SqlServer.Management.Sdk.Sfc.dll

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-05
        • 2013-01-15
        • 2010-09-17
        • 2020-11-26
        • 2020-05-22
        • 2023-03-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多