Резервное копирование базы данных через SMO (объекты управления SQL Server) в C#

Мне нужно сделать резервную копию базы данных (используя SQL Server 2008 R2). Размер базы данных составляет около 100 ГБ, поэтому я хочу создать резервную копию только важных таблиц (содержащих настройки) и, конечно же, объектов всех таблиц, представлений, триггеров и т. д.

Например:

  • db: Products
  • столов: Food, Clothes, Cars

В Cars слишком много автомобилей, поэтому я сделаю резервную копию только определения таблицы (CREATE TABLE ...) и заполню Food и Clothes (включая их содержимое).

Посоветуйте лучшее решение, пожалуйста. Я, вероятно, буду использовать SMO (если нет лучшего решения). Должен ли я использовать класс Backup? Или Scripter класс? Или другой (если есть)? Какой класс может справиться с моими требованиями?

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

Буду признателен за образец кода. Написано в ответе или где-то (ссылка на сообщение), но убедитесь, что во внешней статье есть решение именно для такой проблемы.

Вы можете использовать эту часть кода

ServerConnection connection = new ServerConnection("SERVER,1234", "User", "User1234");
Server server = new Server(connection);
Database database = server.Databases["DbToBackup"];

person Ondrej Janacek    schedule 13.09.2011    source источник
comment
Почему вы не можете сделать резервную копию через SQL Management Studio?   -  person David Anderson    schedule 13.09.2011
comment
Потому что это не мой сервер. Я только кодирую приложение для клиента. Он новичок в IT, сам не справится.   -  person Ondrej Janacek    schedule 13.09.2011
comment
Обычное резервное копирование SQL Server работает только на уровне базы данных или группы файлов — вы не можете выборочно создавать резервные копии одних таблиц и опускать другие. Если вы хотите написать скрипт на SQL, вам нужно использовать SMO и класс Scripter — не уверен, что он поддерживает также скриптирование содержимого таблиц — вам придется попробовать.   -  person marc_s    schedule 13.09.2011
comment
Верно, но вы можете выборочно экспортировать свои данные как таковые в повторно используемый формат. «Резервное копирование» зависит от контекста.   -  person David Anderson    schedule 13.09.2011
comment
Спасибо marc_s за редактирование моего поста. Это выглядит лучше :)   -  person Ondrej Janacek    schedule 13.09.2011


Ответы (3)


Использование СМО. Вам придется поиграть с нужными вам параметрами.

StringBuilder sb = new StringBuilder();
using (SqlConnection connection = new SqlConnection("connectionString")) {
    ServerConnection serverConnection = new ServerConnection(connection);
    Server server = new Server(serverConnection);
    Database database = server.Databases["databaseName"];
    Scripter scripter = new Scripter(server);
    scripter.Options.ScriptDrops = false;
    scripter.Options.WithDependencies = true;
    scripter.Options.ScriptData = true;
    Urn[] smoObjects = new Urn[1];
    foreach (Table table in database.Tables) {
        smoObjects[0] = table.Urn;
        if (!table.IsSystemObject) {
            foreach (string s in scripter.EnumScript(smoObjects)) {
                System.Diagnostics.Debug.WriteLine(s);
                sb.AppendLine(s);
            }
        }
    }
}
// Write to *.sql file on disk
File.WriteAllText(@".\backup.sql");

Еще один простой способ сделать это — создать резервную копию базы данных в xml-файлах. Для этого используйте DataTable и вызовите WriteXml и WriteXmlSchema. (Вам понадобится схема позже, чтобы ее можно было импортировать/восстановить, используя тот же метод). Этот метод означает, что вы выполняете резервное копирование для каждой таблицы.

private bool BackupTable(string connectionString, string tableName, string directory) {
    using (SqlConnection connection = new SqlConnection(connectionString)) {
        try {
            connection.Open();
        }
        catch (System.Data.SqlClient.SqlException ex) {
            // Handle
            return false;
        }
        using (SqlDataAdapter adapter = new SqlDataAdapter(string.Format("SELECT * FROM {0}", tableName), connection)) {
            using (DataTable table = new DataTable(tableName)) {
                adapter.Fill(table);
                try {
                    table.WriteXml(Path.Combine(directory, string.Format("{0}.xml", tableName)));
                    table.WriteXmlSchema(Path.Combine(directory, string.Format("{0}.xsd", tableName)));
                }
                catch (System.UnauthorizedAccessException ex) {
                    // Handle
                    return false;
                }
            }
        }
    }
    return true;
}

Позже вы можете отправить их обратно в базу данных, используя ReadXmlSchema и ReadXml, используя адаптер для заполнения и обновления таблицы в базе данных. Я предполагаю, что вы разбираетесь в основах CRUD, поэтому мне не нужно освещать эту часть.

Если вы хотите использовать SMO, вот статья Msdn об использовании классов резервного копирования и восстановления для резервного копирования и восстановления базы данных. Пример кода был неформатирован и написан на VB.NET, но легко переводим.

Наконец, что может быть проще, поговорите с ИТ-специалистами и узнайте, разрешат ли они вам удаленно или дадут вам доступ для самостоятельного резервного копирования. Если вы пишете программное обеспечение, и это важный шаг, сообщите им, насколько это важно для вас, так как это снизит затраты на написание собственного инструмента, когда уже существуют отличные инструменты. Тем более, что база данных составляет 100 ГБ, вы можете использовать инструменты, которые, как вы знаете, уже работают.

person David Anderson    schedule 13.09.2011
comment
Прочитайте правильно мой вопрос, пожалуйста. Я хочу создать резервную копию этих файлов в файлах *.sql. - person Ondrej Janacek; 13.09.2011
comment
Я это прекрасно понимаю, но это непростая задача, для которой можно легко найти ресурсы без часов исследований. Существуют лучшие решения, такие как использование мастера публикации базы данных SQL Server, который делает именно то, что вам нужно, и если он подходит для вашей ситуации. Вы даже можете попробовать weblogs.asp.net/shahar/archive/2010/03/03/, но это тоже выглядит отрывочно. Это также может помочь: sqlservercentral.com/articles/SMO/scriptdatabaseobjectswithsmo/ - person David Anderson; 13.09.2011
comment
Я закончил это час назад благодаря URL, который вы разместили в своем комментарии. Я тоже нашел. Но мне пока не разрешено отвечать на мой собственный вопрос, поэтому завтра я опубликую рабочее решение. - person Ondrej Janacek; 13.09.2011
comment
Я также обновил свой ответ рабочим решением для вас. - person David Anderson; 13.09.2011
comment
О, я вижу знакомые команды. Я ценю ваш интерес, может ваше решение поможет другим. Я все еще собираюсь опубликовать свое решение как лучшее решение, потому что оно лучше всего подходит для моей проблемы. Если вы понимаете тот код, который вы публикуете, завтра вы увидите более подходящий вариант, не нужны объекты Urn, не нужны объекты scripter. Но все равно спасибо :) - person Ondrej Janacek; 14.09.2011

Эта статья была достаточно информативной, чтобы решить мою проблему. Вот мое рабочее решение. Я решил записать все объекты в один файл, я думаю, это лучшее решение из-за зависимостей. Если в каждом файле есть одна таблица, а также есть некоторые зависимости (например, внешние ключи), будет больше кода, чем если бы все было в одном файле.

Я пропустил некоторые части кода в этом примере, например резервное копирование файлов резервных копий на случай неправильного резервного копирования базы данных. Если такой системы нет, все резервные копии будут записываться в один файл, и это будет беспорядочно.

public class DatabaseBackup
{
    private ServerConnection Connection;
    private Server Server;
    private Database Database;
    private ScriptingOptions Options;
    private string FileName;
    private const string NoDataScript = "Cars";

    public DatabaseBackup(string server, string login, string password, string database)
    {
        Connection = new ServerConnection(server, login, password);
        Server = new Server(Connection);
        Database = Server.Databases[database];
    }

    public void Backup(string fileName)
    {
        FileName = fileName;
        SetupOptions();

        foreach (Table table in Database.Tables)
        {
             if (!table.IsSystemObject)
             {
                  if (NoDataScript.Contains(table.Name))
                  {
                       Options.ScriptData = false;
                       table.EnumScript(Options);
                       Options.ScriptData = true;
                  }
                  else
                       table.EnumScript(Options);
              }
         }
    }

    private void SetupOptions()
    {
         Options = new ScriptingOptions();
         Options.ScriptSchema = true;
         Options.ScriptData = true;
         Options.ScriptDrops = false;
         Options.WithDependencies = true;
         Options.Indexes = true;
         Options.FileName = FileName;
         Options.EnforceScriptingOptions = true;
         Options.IncludeHeaders = true;
         Options.AppendToFile = true;
    }
}
person Ondrej Janacek    schedule 14.09.2011

То, что вы описываете, на самом деле не является резервным копированием, но я понимаю, какова ваша цель:

Для «Резервного копирования» данных вы можете загрузить содержимое таблицы через Reader в DataTable и сохранить результат в виде XML...

person Yahia    schedule 13.09.2011