web-dev-qa-db-ja.com

C#から.sqlを実行するにはどうすればよいですか?

一部の統合テストでは、データベースに接続して、GOステートメントを含め、テストを実際に実行するために必要なスキーマを含む.sqlファイルを実行したいと思います。どうすれば.sqlファイルを実行できますか? (またはこれは完全に間違った方法ですか?)

私は見つけました MSDNフォーラムの投稿 このコードを示しています:

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どこかからダウンロードするように言われましたが、それは非常にハッキーに聞こえます。よりクリーンな方法はありますか?別の方法はありますか?何が間違っているのですか?

これは、Visual Studio 2008、SQL Server 2008、.Net 3.5SP1、およびC#3.0で行っています。

15
pupeno
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ライブラリ 「GO」キーワードをサポートしていません 。オプションは次のようです。

  1. スクリプトを解析します。 'GO'キーワードを削除し、スクリプトを個別のバッチに分割します。各バッチを独自のSqlCommandとして実行します。
  2. スクリプトをシェルのSQLCMDに送信します(David Andresの回答)。
  3. ブログ投稿のコードのようにSMOを使用します。

実際、この場合、SMOが最善の選択肢かもしれないと思いますが、dllが見つからなかった理由を突き止める必要があります。

29
Matt Brunell

MSVCR80は、Visual C++ 2005ランタイムです。ランタイムパッケージのインストールが必要になる場合があります。詳細については、 http://www.Microsoft.com/downloads/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647&displaylang=en を参照してください。

DLLの問題とMattBrunellの答え(あなたがやろうとしていることにもっと適していると思います)を解決することに加えて、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 を参照してください。

9
David Andres

コードから生成されたデータベーススクリプトを自動的に実行する必要があるのと同じように、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のステートメントが含まれており、520kBです。

2
Anlo

プロジェクトに次の参照を追加すると、元のコードが正常に機能します。

SQL 2008Expressを使用しています。

パス:C:\ Program Files(x86)\ Microsoft SQL Server\100\SDK\Assembly \

ファイル:Microsoft.sqlserver.smo.dll、Microsoft.sqlserver.connectioninfo.dll、Microsoft.SqlServer.Management.Sdk.Sfc.dll

0
Miguel

.sqlファイルの非常に基本的なスクリプトでこれを実行してみましたか?たぶん、1つの行を挿入するだけ、または任意のテーブルを作成するものですか?確認が非常に簡単なものはありますか?基本的に、このコードは、ファイルから読み取ることを除けば、SQLをハードコーディングするようなものです。非常に単純なファイルで動作させることができれば、ファイル構造自体に何か問題がある可能性が高いと言えます。投稿は、ファイルに含めることができるものとできないものに関していくつかの規定があるという事実をほのめかしました。他に何もないとしても、トラブルシューティングを開始するのに適した場所です。

0
Chris Thompson

あなたはこれに興味があるかもしれません: http://geekswithblogs.net/thomasweller/archive/2009/09/08/automating-database-script-execution.aspx

これは、SQLスクリプトを自動的に実行するための汎用の「テストフィクスチャ」を提供します。利用可能なサンプルコードもあり、異常なアセンブリへの依存関係はまったくありません...

0
Thomas Weller