Подтвердить что ты не робот

Использование SMO для копирования базы данных и данных

Я пытаюсь сделать копию базы данных для новой базы данных на том же сервере. Сервер - это мой локальный компьютер с SQL 2008 Express под Windows XP. Для этого достаточно просто использовать класс 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();
        }
    }
}

Что я здесь делаю, это сначала создать новую базу данных, затем сгенерировать копию script с помощью класса Transfer и, наконец, запустить script в новой базе данных.

Это отлично подходит для копирования структуры, но параметр CopyData не работает!

Существуют ли какие-либо недокументированные лимиты для опции CopyData? В документации только говорится, что параметр указывает, будут ли данные скопированы.

Я попытался использовать метод TransferData() для копирования базы данных без использования script, но затем я получаю исключение, в котором говорится: "Не удалось подключиться к серверу" с внутренним исключением, которое говорит "Связанный с сетью или экземпляр- произошла ошибка при установлении соединения с SQL Server. Сервер не был найден или недоступен. Убедитесь, что имя экземпляра верное и что SQL Server настроен на разрешение удаленных подключений. (поставщик: поставщик именованных труб, ошибка: 40 - Не удалось открыть соединение с SQL Server)"

Я также попытался включить Named Pipes на сервере, но это не помогает.

Изменить: Я нашел решение, которое работает, создав резервную копию, а затем восстановив ее в новой базе данных. Это довольно неуклюже, хотя и медленнее, чем должно быть, поэтому я все еще ищу лучшее решение.

4b9b3361

Ответ 1

Хорошо, после того, как я связался с Microsft Support, я получил правильную работу, но он медленный и более или менее бесполезный. Выполнение резервного копирования, а затем восстановление происходит намного быстрее, и я буду использовать его, пока новая копия должна жить на том же сервере, что и оригинал.

Рабочий код выглядит следующим образом:

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. Это должно быть установлено, даже если цель та же, что и источник. Кроме того, мне пришлось подключаться к серверу как именованный экземпляр вместо использования других параметров подключения.

Ответ 2

У меня было желание получить эту работу и придумал ответ, который не использует класс 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();
       }
   }

Ответ 3

Попробуйте установить SetDefaultInitFields в true на Сервер.

>

У меня была такая же проблема, что и объект базы данных SMO. Я полагаю, это связано с тем, что сервер sql не любит извлекать целые объекты и коллекции сразу, вместо этого ленивая загрузка всего, что вызывает обратную связь для каждого поля, что для всей базы данных довольно неэффективно.

Ответ 4

Вот мое решение:

  • У меня есть база данных, называемая Olddatabase
  • Я резервирую его в E:\databackup\Old.bak

  • Если вы хотите создать Duplicate Database из Olddatabase на том же сервере с именем NewDatabase

3.1. Вы можете использовать команду в инструменте запросов: EXEC OldDatabase.dbo.sp_helpfile; для определения пути OldDatabase хранится в случае, если вы хотите сохранить NewDatabase в той же папке.

или Вы можете сохранить NewDatabase в новом пути, который вы хотите

  • используйте эту команду в инструменте запросов

    ВОССТАНОВИТЬ БАЗА ДАННЫХ NewDatabase FROM DISK = 'E:\databackup\Old.bak' С MOVE 'OldDatabase' TO 'E:\Новый путь (или тот же путь)\NewDatabase_Data.mdf', MOVE 'OldDatabase_log' TO 'E:\Новый путь (или тот же путь)\NewDatabase_Log.ldf';

Примечание. Вы можете использовать эту команду в С# с помощью: Создать процедуру Store в sql, которая включает команды Above. И вы можете вызвать процедуру хранилища в С#