22

同じサーバー上の新しいデータベースにデータベースのコピーを作成しようとしています。サーバーは、WindowsXPでSQL2008Expressを実行しているローカルコンピューターです。これを行うには、SMO.Transferクラスを使用すると非常に簡単で、ほとんど機能します。

私のコードは次のとおりです(やや簡略化されています):

Server server = new Server("server");
Database sourceDatabase = server.Databases["source database"];

Database newDatbase = new Database(server, "new name");
newDatbase.Create();

Transfer transfer = new Transfer(sourceDatabase);
transfer.CopyAllObjects = true;
transfer.Options.WithDependencies = true;
transfer.DestinationDatabase = newDatbase.Name;
transfer.CopySchema = true;
transfer.CopyData = true;
StringCollection transferScript = transfer.ScriptTransfer();

using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    using (SqlCommand switchDatabase = new SqlCommand("USE " + newDatbase.Name, conn))
    {
        switchDatabase.ExecuteNonQuery();
    }

    foreach (string scriptLine in transferScript)
    {
        using (SqlCommand scriptCmd = new SqlCommand(scriptLine, conn, transaction))
        {
            int res = scriptCmd.ExecuteNonQuery();
        }
    }
}

ここで行うことは、最初に新しいデータベースを作成し、次にTransferクラスを使用してコピースクリプトを生成し、最後に新しいデータベースでスクリプトを実行することです。

これは構造をコピーするためにうまく機能しますが、CopyDataオプションは機能しません!

オプションに文書化されていない制限はありCopyDataますか?ドキュメントには、オプションでデータをコピーするかどうかを指定するだけであると記載されています。

TransferData()スクリプトを使用せずにデータベースをコピーするメソッドを使用しようとしましたが、「サーバーへの接続に失敗しました」という例外が発生し、「への接続の確立中にネットワーク関連またはインスタンス固有のエラーが発生しました」という内部例外が発生します。 SQL Server。サーバーが見つからないか、アクセスできませんでした。インスタンス名が正しいこと、およびSQL Serverがリモート接続を許可するように構成されていることを確認してください(プロバイダー:Named Pipes Provider、エラー:40-SQLServerへの接続を開くことができませんでした)」

また、サーバーで名前付きパイプを有効にしようとしましたが、それは役に立ちません。

編集:バックアップを作成してから新しいデータベースに復元することで機能するソリューションを見つけました。しかし、それはかなり不器用で、本来よりも遅いので、私はまだより良い解決策を探しています。

4

4 に答える 4

18

Microsft サポートに連絡したところ、正常に動作するようになりましたが、動作が遅く、多かれ少なかれ役に立ちません。バックアップを行ってから復元する方がはるかに高速であり、新しいコピーが元のサーバーと同じサーバーにある限り、私はそれを使用します.

作業コードは次のとおりです。

ServerConnection conn = new ServerConnection("rune\\sql2008");
Server server = new Server(conn);

Database newdb = new Database(server, "new database");
newdb.Create();

Transfer transfer = new Transfer(server.Databases["source database"]);
transfer.CopyAllObjects = true;
transfer.CopyAllUsers = true;
transfer.Options.WithDependencies = true;
transfer.DestinationDatabase = newdb.Name;
transfer.DestinationServer = server.Name;
transfer.DestinationLoginSecure = true;
transfer.CopySchema = true;
transfer.CopyData = true;
transfer.Options.ContinueScriptingOnError = true;
transfer.TransferData();

秘訣は、DestinationDatabase プロパティを設定することでした。これは、ターゲットがソースと同じであっても設定する必要があります。さらに、他の接続オプションを使用する代わりに、名前付きインスタンスとしてサーバーに接続する必要がありました。

于 2008-11-26T14:28:42.577 に答える
3

私はこれを機能させることに挑戦し、Transfer クラスを使用しない答えを思いつきました。これが私が使用した方法です:

       public bool CreateScript(string oldDatabase, string newDatabase)
   {
       SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=" + newDatabase + ";User Id=sa;Password=sa;");
       try
       {
           Server sv = new Server();
           Database db = sv.Databases[oldDatabase];

           Database newDatbase = new Database(sv, newDatabase);
           newDatbase.Create(); 

           ScriptingOptions options = new ScriptingOptions();
           StringBuilder sb = new StringBuilder();
           options.ScriptData = true;
           options.ScriptDrops = false;
           options.ScriptSchema = true;
           options.EnforceScriptingOptions = true;
           options.Indexes = true;
           options.IncludeHeaders = true;
           options.WithDependencies = true;

           TableCollection tables = db.Tables;

           conn.Open();
           foreach (Table mytable in tables)
           {
               foreach (string line in db.Tables[mytable.Name].EnumScript(options))
               {
                   sb.Append(line + "\r\n");
               }
           }
           string[] splitter = new string[] { "\r\nGO\r\n" };
           string[] commandTexts = sb.ToString().Split(splitter, StringSplitOptions.RemoveEmptyEntries);
           foreach (string command in commandTexts)
           {
               SqlCommand comm = new SqlCommand(command, conn);
               comm.ExecuteNonQuery();
           }
           return true;
       }
       catch (Exception e)
       {
           System.Diagnostics.Debug.WriteLine("PROGRAM FAILED: " + e.Message);
           return false;
       }
       finally
       {
           conn.Close();
       }
   }
于 2011-10-18T13:25:35.397 に答える
2

ServerオブジェクトでSetDefaultInitFieldsを true に設定してみてください。

SMO データベース オブジェクトの実行速度が遅いという同じ問題がありました。これは、SQLサーバーがオブジェクトとコレクション全体を一度に取得するのを好まず、代わりにすべてを遅延ロードして各フィールドのラウンドトリップを引き起こし、データベース全体ではかなり非効率的であるためだと思います。

于 2009-06-23T06:07:04.387 に答える
1

これが私の解決策です:

  1. Olddatabaseという名前のデータベースがあります
  2. E:\databackup\Old.bak にバックアップします

  3. NewDatabase という名前の同じサーバーで Olddatabase から複製データベースを作成する場合

3.1 クエリ ツールでコマンドを使用できます。EXEC OldDatabase.dbo.sp_helpfile; NewDatabase を同じフォルダに保存する場合に備えて、OldDatabase のパスを決定します。

または、必要な新しいパスに NewDatabase を保存できます

  1. クエリ ツールでこのコマンドを使用します

    RESTORE DATABASE NewDatabase FROM DISK = 'E:\databackup\Old.bak' WITH MOVE 'OldDatabase' TO 'E:\New path (または同じパス)\NewDatabase_Data.mdf', MOVE 'OldDatabase_log' TO 'E:\New path (または同じパス)\NewDatabase_Log.ldf';

注: これらのコマンド obove を c# で使用できます: 上記のコマンドを含む SQL で Store プロシージャを作成します。そして、C# でストア プロシージャを呼び出すことができます

于 2013-12-08T14:22:52.303 に答える