2008-11-06 76 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#调用存储过程。