C# - Backup e Restauração de banco de dados SQL Server


 Neste artigo vou mostrar como realizar o backup e a restauração de um banco de dados SQL Server usando os recursos do SQL Server Management Objects (SMO).

O backup e a restauração de um banco de dados é uma tarefa crítica pois visa manter a integridade e a segurança das informações armazenadas.

Para grandes aplicações a realização do backup e restauração em geral fica sob responsabilidade de um DBA, mas para aplicações menores a responsabilidade fica por conta do desenvolvedor e isso pode ser uma tarefa espinhosa visto que temos diversas versões do SQL Server, diversos tipos de backups, etc.

Neste artigo eu vou mostrar como podemos realizar a restauração e o backup do banco de dados SQL Server em uma aplicação Windows Forms usando a linguagem C# para a versão do SQL Server 2012 e utilizando os recursos do SQL Server Management Objects (SMO) que é uma coleção de namespaces que, por sua vez, contêm diferentes classes, interfaces, delegados e enumerações, para trabalhar e gerenciar uma instância do SQL Server via programação.

O SMO estende e substitui os Objetos de Gerenciamento Distribuído do SQL Server (SQL-DMO) que foi usado para versões mais antigas do SQL Server (SQL Server 2000). Portanto veremos como usar o SMO e como gerenciar programaticamente uma instância do SQL Server usando C#.

Nota: Os aplicativos que usam SMO e que foram escritos usando versões anteriores do SQL Server podem ser recompilados usando SMO no SQL Server atual.  As referências a dlls do SMO em versões antigas do SQL Server devem ser removidas e as referências às novas dll do SMO fornecidas com o SQL Server atual devem ser incluídas.

Apresentando o SMO

O modelo de objeto SMO representa o SQL Server como uma hierarquia de objetos. No topo dessa hierarquia esta o objeto Server, abaixo dele residem todas as demais classes de instância.

As classes SMO podem ser agrupadas em duas categorias:

- Classes de instância - Os objetos do SQL Server são representados por classes de instância. Elas formam uma hierarquia que se assemelha à hierarquia de objetos do servidor de banco de dados. No topo desta hierarquia esta o objeto Server e, por isso, existe uma hierarquia de objetos de instância que incluem: bancos de dados, tabelas, colunas, triggers , índices, funções definidas pelo usuário, procedimentos armazenados, etc.

- Classes de utilidade - As classes de utilidade são independentes da instância do SQL Server e executam tarefas específicas. Essas classes foram agrupadas com base em suas funcionalidades. Por exemplo, operações de script de banco de dados, bancos de dados de backup e restauração, transferência de esquema e dados para outro banco de dados etc.

Em geral para poder usar esses recursos você deverá usar as seguintes referências:

Além dessas classes temos também as classes dos seguintes namespaces:

Microsoft.SqlServer.Management.Common Contém as classes que você precisará para estabelecer uma conexão com uma instância do SQL Server e executar instruções Transact-SQL diretamente.
Microsoft.SqlServer.Management.Smo Este é o namespace básico que você precisará em todos os aplicativos SMO, ele fornece classes para funcionalidades SMO essenciais. Ele contém classes de utilidade, classes de instâncias, enumerações, tipos de manipuladores de eventos e diferentes tipos de exceções.
Microsoft.SqlServer.Management.Smo.Agent Fornece as classes para gerenciar o SQL Server Agent, por exemplo, para gerenciar Job, Alerts etc.
Microsoft.SqlServer.Management.Smo.Broker Fornece classes para gerenciar componentes do Service Broker usando SMO.
Microsoft.SqlServer.Management.Smo.Wmi Fornece classes que representam o SQL Server Windows Management Instrumentation (WMI). Com essas classes, você pode iniciar, parar e pausar os serviços do SQL Server, alterar os protocolos e as bibliotecas de rede, etc

Instalando o SMO

Para podermos usar os recursos do SMO temos que instalar você deve selecionar o SDK de Ferramentas do Cliente quando instalar o SQL Server. Para instalar o Client Tooks SDK sem instalar o SQL Server, instale o Shared Management Objects do pacote de recursos do SQL Server.

Se você quiser garantir que o SQL Server Management Objects esteja instalado em um computador que executará seu aplicativo, você pode usar os Shared Management Objects(Objetos de gerenciamento compartilhado) .msi no pacote de recursos do SQL Server.

Por padrão, os assemblies SMO estão instalados no diretório
C:\Program Files\Microsoft SQL Server\130\SDK\Assemblies\

Você referencia os pacotes em seu projeto clicando com o botão direito do mouse sobre o nome do projeto e selecionando a opção Add Reference.

 

Cabe ressaltar que podemos ter os seguintes tipos de backup no SQL Server:

  1. Full Backups

  2. Differential Backups

  3. Transaction Log Backups

  4. Backup with Compression

  5. Full or Differential Restores

Recursos Usados :

Criando o projeto no VS 2017 Community

Abra o VS 2017 Community e crie um novo projeto (File-> New Project) usando a linguagem Visual C# e o template Windows Classic Desktop ->Windows Forms Application(.NET Framework)

Informe um nome a seu gosto. Eu vou usar o nome CShp_SQLServerBackupRestore.

A seguir inclua as referências ao SMO via menu Project opção Add Reference :

A partir da ToolBox inclua os seguints controles no formulário:

Disponha os controles conforme o leiaute da figura baixo:

Defina os seguintes namespaces no formulário :

using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using System;
using System.Data;
using System.IO;
using System.Windows.Forms;

Declare as seguintes variáveis no formulário:

 //enumera uma lista de instâncias locais disponíveis do SQL Server
DataTable tabelaServidores = SmoApplication.EnumAvailableSqlServers(true);
//define o objeto do tipo Server
private static Server servidor;
//define o caminho para o backup/restore (pasta bin/Debug)
private string DBpath = Application.StartupPath;

1- No evento Load do formulário digite o código abaixo:

 private void Form1_Load(object sender, EventArgs e)
        {
            this.Cursor = Cursors.Default;
            WindowState = FormWindowState.Normal;
            cboServidor.Enabled = false;
            cboDataBase.Enabled = false;
            try
            {
                chkIntegratedSecurity.Checked = true;
                // Se existerem servidores
                if (tabelaServidores.Rows.Count > 0)
                {
                    // Percorre cada servidor na tabela
                    foreach (DataRow drServer in tabelaServidores.Rows)
                    {
                        cboServidor.Items.Add(drServer["Name"]);
                        cboServidor.Text = Convert.ToString(drServer["Name"]);
                    }
                }
            }
            catch (Exception)
            {
                // Inicie o serviço do SQL Server Browser se não conseguir carregar os servidores.(http://msdn.microsoft.com/en-us/library/ms165734(v=sql.90).aspx
                MessageBox.Show("ERROR: Não existem servidores disponíveis.\nOu ocorreu um erro ao carregar os servidores", "Servidor Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
            this.Cursor = Cursors.Default;
        }
 

O código já esta comentado mas vale ressaltar a operação de carregar o combobox com as instâncias locais do SQL Server pode demorar. Se por algum motivo não carregar nenhuma instância então tente habilitar o serviço do SQL Server Browser.

A seguir o código do evento SelectedValueChanged dos combobox que desabilita os combox e o código do evento Click dos botões Alterar (servidor e database) habilita os combobox:

       private void cboServidor_SelectedValueChanged(object sender, EventArgs e)
        {
            //habilita o combobox dos servidores
            cboServidor.Enabled = false;
        }
        private void cboDataBase_SelectedValueChanged(object sender, EventArgs e)
        {
            //habilita o combobox dos databases
            cboDataBase.Enabled = false;
        }
        private void btnAlterarDatabase_Click(object sender, EventArgs e)
        {
             //habilita o combobox dos databases
            cboDataBase.Enabled = true;
        }
        private void btnAlterarServidor_Click(object sender, EventArgs e)
        {
            //habilita o combobox dos servidores
            cboServidor.Enabled = true;
        }

Código do evento CheckedChanged do controle CheckBox que verifica se esta marcado ou não e altera as propriedades dos TextBox para o usuário e senha:

        private void chkIntegratedSecurity_CheckedChanged(object sender, EventArgs e)
        {
            //verifica se o checkbox esta marcado ou desmarcado e altera as propriedades dos TextBox
            if (chkIntegratedSecurity.CheckState == CheckState.Checked)
            {
                txtUsuario.Enabled = false;
                txtUsuario.Text = string.Empty;
                txtSenha.Enabled = false;
                txtSenha.Text = string.Empty;
            }
            if (chkIntegratedSecurity.CheckState == CheckState.Unchecked)
            {
                txtUsuario.Enabled = true;
                txtSenha.Enabled = true;
            }
        }

Código do evento Click do combobox - cboDataBase - que carrega o controle com o nome dos bancos de dados selecionados para a instância do servidor selecionada:

       private void cboDataBase_Click(object sender, EventArgs e)
        {
            //limpa o combobox dos databases
            cboDataBase.Items.Clear();
            try
            {
                //se foi selecionado um servidor
                if (cboServidor.SelectedItem != null && cboServidor.SelectedItem.ToString() != "")
                {
                    this.Cursor = Cursors.WaitCursor;
                    // Cria uma nova conexão com o servidor selecionado
                    ServerConnection srvConn = new ServerConnection(cboServidor.SelectedItem.ToString());
                    // Faz o Login usando a autenticacao SQL ao invés da autenticação do Windows
                    srvConn.LoginSecure = true;
                    //tipo de conexão não exige usuário e senha(usa a autenticação do windows)
                    if (chkIntegratedSecurity.CheckState == CheckState.Checked)
                    {
                        // Cria um novo objeto SQL Server usando a conexão criada
                        servidor = new Server(srvConn);
                        // percorre a lista de banco de dados
                        foreach (Database dbServer in servidor.Databases)
                        {
                            // Adiciona o banco de dados na combobox
                            cboDataBase.Items.Add(dbServer.Name);
                        }
                    }
                    //tipo de conexão exige usuário e senha
                    if (chkIntegratedSecurity.CheckState == CheckState.Unchecked)
                    {
                        // atribui o nome do usuário
                        srvConn.Login = txtUsuario.Text;
                        // atribui a senha
                        srvConn.Password = txtSenha.Text;
                        // Cria um novo objeto SQL Server usando a conexão criada
                        servidor = new Server(srvConn);
                        // percorre a lista de banco de dados
                        foreach (Database dbServer in servidor.Databases)
                        {
                            // Adiciona o banco de dados na combobox
                            cboDataBase.Items.Add(dbServer.Name);
                        }
                    }
                }
                else
                {
                    // Um servidor não foi selecionado exibe um erro
                    MessageBox.Show("ERROR: Contate o Administrador!!", "Servidor", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception)
            {
                // Inicie o serviço do SQL Server Browser se não conseguir carregar os servidores.(http://msdn.microsoft.com/en-us/library/ms165734(v=sql.90).aspx
                MessageBox.Show("ERROR: Ocorreu um erro durante a carga dos banco de dados disponíveis", "Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Arrow;
            }
        }

Executando o projeto iremos obter o seguinte resultado:

Agora defina o seguinte código no evento Click do botão de comando Backup:

  private void btnBackup_Click(object sender, EventArgs e)
        {
            //verifica se um banco de dados foi selecionado
            if (cboDataBase.SelectedIndex.ToString().Equals(""))
            {
                MessageBox.Show("Selecione um Database", "Server", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            //se o objeto servidor for diferente de null temos uma conexão
            if (servidor != null)
            {
                try
                {
                    //desabilita os botões
                    btnBackup.Enabled = false;
                    btnRestore.Enabled = false;
                    btnAlterarDatabase.Enabled = false;
                    btnAlterarServidor.Enabled = false;
                    //Este codigo é usado se você já criou o arquivo de backup.
                    File.Delete(DBpath + "\\backup.bak");
                    this.Cursor = Cursors.WaitCursor;
                    // se o usuário escolheu um caminho onde salvar o backup
                    // Cria uma nova operação de backup
                    Backup bkpDatabase = new Backup();
                    // Define o tipo de backup type para o database
                    bkpDatabase.Action = BackupActionType.Database;
                    // Define o database que desejamos fazer o backup
                    bkpDatabase.Database = cboDataBase.SelectedItem.ToString();
                    // Define o dispositivo do backup para : file
                    BackupDeviceItem bkpDevice = new BackupDeviceItem(DBpath + "\\Backup.bak", DeviceType.File);
                    // Adiciona o dispositivo de backup ao backup
                    bkpDatabase.Devices.Add(bkpDevice);
                    // Realiza o backup
                    bkpDatabase.SqlBackup(servidor);
                    MessageBox.Show("Backup do Database " + cboDataBase.Text + " criado com sucesso", "Servidor", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception x)
                {
                    MessageBox.Show("ERRO: Ocorreu um erro durante o BACKUP do DataBase" + x, "Erro no Servidor", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    this.Cursor = Cursors.Arrow;
                    //habilita os botões
                    btnBackup.Enabled = true;
                    btnRestore.Enabled = true;
                    btnAlterarDatabase.Enabled = true;
                    btnAlterarServidor.Enabled = true;
                }
            }
            else
            {
                MessageBox.Show("ERRO: Não foi estabelecida uma conexão com o SQL Server", "Servidor", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Cursor = Cursors.Arrow;
            }
        }

Lembrando que o backup foi definido para o tipo de dispositivo FILE e que o arquivo .bak  será copiado na pasta \bin\debug do projeto.

Código do evento Click do botão Restore :

        private void btnRestore_Click(object sender, EventArgs e)
        {
            //verifica se foi selecoinado um banco de dados
            if (cboDataBase.SelectedIndex.ToString().Equals(""))
            {
                MessageBox.Show("Escolha um banco de dados", "Servidor", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            // Se existir um conexão SQL Server criada
            if (servidor != null)
            {
                try
                {
                    //desabilita os botões
                    btnBackup.Enabled = false;
                    btnRestore.Enabled = false;
                    btnAlterarDatabase.Enabled = false;
                    btnAlterarServidor.Enabled = false;
                    this.Cursor = Cursors.WaitCursor;
                    // Se foi escolhido o arquivo o arquivo que deseja ser restaurado
                    // Cria uma nova operação de restore
                    Restore rstDatabase = new Restore();
                    // Define o tipo de restore para o banco de dados
                    rstDatabase.Action = RestoreActionType.Database;
                    // Define o database que desejamos restaurar
                    rstDatabase.Database = cboDataBase.SelectedItem.ToString();
                    // Define o dispostivo de backup a partir do qual vamos restaurar o arquivo
                    BackupDeviceItem bkpDevice = new BackupDeviceItem(DBpath + "\\Backup.bak", DeviceType.File);
                    // Adiciona o dispositivo de backup ao tipo de restore
                    rstDatabase.Devices.Add(bkpDevice);
                    // Se o banco de dados ja existe então subsititui
                    rstDatabase.ReplaceDatabase = true;
                    // Realiza o Restore
                    rstDatabase.SqlRestore(servidor);
                    MessageBox.Show("Database " + cboDataBase.Text + " RESTAURADO com sucesso", "Servidor", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception)
                {
                    MessageBox.Show("ERRO: Ocorreu um erro durante a restauração do banco de dados", "Erro na aplicação", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    this.Cursor = Cursors.Arrow;
                    //habilita os botões
                    btnBackup.Enabled = true;
                    btnRestore.Enabled = true;
                    btnAlterarDatabase.Enabled = true;
                    btnAlterarServidor.Enabled = true;
                }
            }
            else
            {
                MessageBox.Show("ERRO: Não foi estabelecida uma conexão com o SQL Server", "Servidor", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Cursor = Cursors.Arrow;
            }
        }

Executando o projeto teremos o seguinte resultado:

O projeto foi testado com o SQL Server 2012. Para versões anteriores pode ser necessário ajustes no código.

Pegue o código do projeto aqui : CShp_SQLServerBackupRestore.zip

Até o próximo artigo...

"E o mundo passa, e a sua concupiscência; mas aquele que faz a vontade de Deus permanece para sempre."
1 João 2:17

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET ?

 

 

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
 

Referências:


José Carlos Macoratti