我正在尝试将数据库的副本复制到同一服务器上的新数据库。服务器是我在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的连接)“
我还尝试在服务器上启用命名管道,但这没有帮助。
编辑: 我找到了一个解决方案,通过进行备份然后将其还原到新数据库。虽然这很笨拙,而且比它应该慢,所以我仍然在寻找更好的解决方案。
答案 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)
这是我的解决方案:
我将其备份到E:\ databackup \ Old.bak
如果要在名为NewDatabase的同一服务器中从Olddatabase创建重复数据库
3.1您可以在查询工具中使用命令:EXEC OldDatabase.dbo.sp_helpfile; 如果要将NewDatabase保存在同一文件夹中,则存储确定OldDatabase的路径。
或者您可以将NewDatabase保存在您想要的新路径中
在查询工具中使用此命令
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';
注意:你可以在c#中使用这些命令obove:在sql中创建一个包含Above命令的store过程。您可以在C#中调用存储过程