sqlserver sharedmanagementobjects objects msi microsoft management connectioninfo c# .net sql-server-2008 smo

c# - sharedmanagementobjects - Usar SMO para copiar una base de datos y datos



sql server 2017 smo (4)

Estoy tratando de hacer una copia de una base de datos a una nueva base de datos en el mismo servidor. El servidor es mi computadora local que ejecuta SQL 2008 Express en Windows XP. Hacer esto debería ser bastante fácil usando la clase SMO.Transfer y ¡casi funciona!

Mi código es el siguiente (algo simplificado):

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

Lo que hago aquí es crear primero una nueva base de datos, luego generar un script de copia usando la clase Transfer y finalmente ejecutar el script en la nueva base de datos.

¡Esto funciona bien para copiar la estructura, pero la opción CopyData no funciona!

¿Hay algún límite no documentado para la opción CopyData ? La documentación solo dice que la opción especifica si los datos se copian.

Intenté usar el método TransferData() para copiar el databse sin usar un script, pero luego recibí una excepción que decía "Falló la conexión al servidor" con una excepción interna que decía "Se produjo un error relacionado con la red o específico de la instancia al establecer una conexión a SQL Server. El servidor no se encontró o no fue accesible. Verifique que el nombre de la instancia sea correcto y que SQL Server esté configurado para permitir conexiones remotas. (provider: proveedor de canalizaciones con nombre, error: 40 - No se pudo abrir una conexión a SQL Server) "

También intenté habilitar Named Pipes en el servidor, pero eso no ayuda.

Editar: Encontré una solución que funciona haciendo una copia de seguridad y luego restaurándola en una nueva base de datos. Sin embargo, es bastante torpe y más lento de lo que debería ser, así que aún estoy buscando una solución mejor.


Bueno, después de contactar al Soporte de Microsft lo conseguí funcionando correctamente, pero es lento y más o menos inútil. Hacer una copia de seguridad y luego una restauración es mucho más rápido y la usaré siempre que la nueva copia viva en el mismo servidor que el original.

El código de trabajo es el siguiente:

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

El truco fue establecer la propiedad DestinationDatabase. Esto debe establecerse incluso si el objetivo es el mismo que el de la fuente. Además, tuve que conectarme al servidor como una instancia nombrada en lugar de usar las otras opciones de conexión.


Intente establecer SetDefaultInitFields en true en el objeto Servidor .

Tuve el mismo problema con el objeto de la base de datos SMO ejecutándose lentamente. Supongo que esto se debe a que al servidor SQL no le gusta recuperar objetos enteros y colecciones a la vez, sino que carga todo de manera lenta, lo que causa un viaje de ida y vuelta para cada campo, lo que para una base de datos completa es bastante ineficiente.


Intenté que esto funcionara y obtuve una respuesta que no utiliza la clase Transferir. Este es el método que utilicé:

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


Aquí está mi solución:

  1. Tengo una base de datos llamada Olddatabase
  2. Lo respaldo a E: / databackup / Old.bak

  3. Si desea crear una base de datos duplicada de Olddatabase en el mismo servidor con el nombre NewDatabase

3.1 Puede usar el comando en la herramienta de consulta: EXEC OldDatabase.dbo.sp_helpfile; para determinar la ruta de OldDatabase se almacena en caso de que desee guardar NewDatabase en la misma carpeta.

o puede guardar NewDatabase en la nueva ruta que desee

  1. usa este comando en la herramienta de consulta

    RESTORE DATABASE NewDatabase FROM DISK = ''E: / databackup / Old.bak'' CON MOVER ''OldDatabase'' TO ''E: / Nueva ruta (o la misma ruta) / NewDatabase_Data.mdf'', MOVE ''OldDatabase_log'' TO ''E: / New ruta (o la misma ruta) / NewDatabase_Log.ldf '';

Nota: puede usar estos comandos obove en c # con: Crear un procedimiento de tienda en sql que incluya los comandos anteriores. Y puede llamar al procedimiento de la tienda en C #