2008-11-06 22 views
20

我想將數據庫的副本複製到同一臺服務器上的新數據庫。服務器是在Windows XP下運行SQL 2008 Express的本地計算機。 使用SMO.Transfer類應該很容易,它幾乎可以工作!使用SMO複製數據庫和數據

我的代碼如下(有些簡化):

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()方法複製DATABSE不使用腳本,但然後我得到,說:「無法連接到服務器」與內部異常,說「發生網絡相關的或特定的情況下,錯誤的異常嘗試同時建立到SQL Server的連接服務器未找到或無法訪問驗證實例名稱是否正確以及SQL Server是否配置爲允許遠程連接(提供程序:命名管道提供程序,錯誤:40 - 無法打開一個連接到SQL Server)「

我也嘗試在服務器上啓用命名管道,但這沒有幫助。

編輯: 我找到了一個解決方案,通過製作備份,然後將其恢復到新的數據庫。儘管這很笨拙,但比預想的要慢,所以我仍然在尋找更好的解決方案。

回答

15

那麼,接觸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屬性。即使目標與源相同,也必須設置該值。另外,我不得不作爲命名實例連接到服務器,而不是使用其他連接選項。

+1

備份和恢復總是會更快,因爲它不受鎖定開銷,事務處理等的影響。備份的設計對於這類事情來說是非常快速的。對不起,我沒有早點找到你! :-D – 2008-12-01 13:13:03

+0

但是,運行備份可能會干擾當前的備份順序和日誌傳輸/截斷。您是否可以使用SMO創建COPY_ONLY備份,如http://msdn.microsoft.com/en-us/library/ms191495.aspx「 – flipdoubt 2010-12-08 15:37:41

2

嘗試將SetDefaultInitFields設置爲服務器對象爲true。

我與SMO數據庫對象運行緩慢相同的問題。我猜這是因爲sql server不喜歡一次檢索整個對象和集合,而是延遲加載所有內容,導致每個字段的往返行程,這對於整個數據庫來說效率非常低。

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(); 
     } 
    } 
1

這裏是我的解決方案:

  1. 我有一個名爲數據庫是Olddatabase
  2. 我備份到E:\ databackup \ Old.bak

  3. 如果要在名稱相同的服務器中使用舊數據庫創建重複數據庫NewDatabase

3.1您可以在查詢工具中使用命令:EXEC OldDatabase.dbo.sp_helpfile; 以確保OldDatabase的路徑存儲在您想要將NewDatabase保存在同一文件夾中的情況下。

也可以保存NewDatabase要在其中

  1. 使用此命令查詢工具

    RESTORE DATABASE NewDatabase FROM DISK新的Path = 'E:\ databackup \ Old.bak' WITH MOVE'OldDatabase'TO'E:\ New path(或相同路徑)\ NewDatabase_Data.mdf', MOVE'OldDatabase_log'TO'E:\ New path(or same path)\ NewDatabase_Log.ldf';

注意:你可以在c#中使用這些命令obove:在sql中創建一個包含上述命令的存儲過程。而且你可以用C#調用存儲過程。