使用SMO复制数据库和数据

时间:2008-11-06 11:42:13

标签: c# .net sql-server-2008 smo

我正在尝试将数据库的副本复制到同一服务器上的新数据库。服务器是我在Windows XP下运行SQL 2008 Express的本地计算机。 使用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是否配置为允许远程连接。(提供者:命名管道提供程序,错误:40 - 无法打开与SQL Server的连接)“

我还尝试在服务器上启用命名管道,但这没有帮助。

编辑: 我找到了一个解决方案,通过进行备份然后将其还原到新数据库。虽然这很笨拙,而且比它应该慢,所以我仍然在寻找更好的解决方案。

4 个答案:

答案 0 :(得分:16)

好吧,在联系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 :(得分: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();
       }
   }

答案 2 :(得分:2)

尝试在服务器对象上将SetDefaultInitFields设置为true。

我遇到了与SMO数据库对象运行缓慢相同的问题。我想这是因为sql server不喜欢一次检索整个对象和集合,而是懒得加载所有内容,导致每个字段的往返,这对整个数据库来说效率很低。

答案 3 :(得分:1)

这是我的解决方案:

  1. 我有一个名为Olddatabase的数据库
  2. 我将其备份到E:\ databackup \ Old.bak

  3. 如果要在名为NewDatabase的同一服务器中从Olddatabase创建重复数据库

  4. 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', 将'OldDatabase_log'移至'E:\新路径(或相同路径)\ NewDatabase_Log.ldf';

    2. 注意:你可以在c#中使用这些命令obove:在sql中创建一个包含Above命令的store过程。您可以在C#中调用存储过程