VB.NET  2005 - Trabalhando com imagens no SQL Server


O propósito deste artigo e mostrar como você pode trabalhar com imagens em um banco de dados SQL Server, como gravar e como carregar imagens de uma tabela em um banco de dados SQL Server 2005.

Vou criar um projeto mostrando passo a passo toda a rotina que você pode usar para realizar a tarefa de tratamento de imagens. Vou aproveitar a tabela Clientes e o arquivo de banco de dados Cadastro.mdf que foram criados em um artigo anterior, mas para que ninguém se sinta prejudicado vou repetir o tópico do artigo que mostra como criar o banco de dados e a tabela no Visual Basic 2005 Express usando o SQL Server Express.

Criando a base de dados no SQL Server 2005 Express

- Abra o VB 2005 Express Edition e crie um novo projeto chamado imgSQLNet.

- Se a janela Data Sources não estiver visível Ative-a no menu Data->Show Data Sources.

- Clique no link Add New Data Source e na janela Data Source Configuration Wizard selecione DataBase.

Nota:  Poderíamos criar a base de dados clicando o botão direito do mouse sobre o nome do projeto e selecione Add->New Item  e na janela de templates selecionar o item SQL Database informando o nome cadastro.mdf para a base de dados a ser criada.

Clique no botão Next> na caixa de combinação selecione a conexão com a base cadastro.mdf. Expandindo a Connection String você verá a string de conexão que será usada para a conexão.

Ao clicar no botão Next> irá surgir a seguinte mensagem de aviso. Ela pergunta se você deseja copiar o arquivo da base de dados cadastro.mdf para o seu projeto. Clique em Não(No) para não salvar o arquivo no seu projeto usando assim o local original onde o mesmo foi criado.

Nota: Veja artigo VB.NET  2005 -  TableAdapater não atualiza os dados  para maiores detalhes sobre o assunto.

Clicando no botão Next> o próximo passo será salvar a string de conexão no arquivo de configuração da aplicação.(Você pode ver o valor clicando em My Project ->Settings)

Neste ponto você deve clicar no botão Cancel para cancelar a operação pois não vamos criar um Data Source. Fizemos os passos acima somente para criar a base de dados e obter a string de conexão.

A string de conexão com o banco de dados usada será armazenada usando o recurso My.Settings conforme os seguintes passos:

  1. Clique com o botão direito sobre My Project na janela Solution Explorer e selecione Open.
  2. Na janela a seguir selecione Settings e informe um nome para a string de conexão e para a string SQL na coluna Name. Eu usei os nomes connSQL. Salve a operação. Pronto ! já podemos recuperar esta informação a partir de My.Settings em tempo de execução.

Criando a tabela Clientes

A próxima etapa será criar uma nova tabela chamada Clientes na base de dados cadastro.mdf.

- Abra a janela do DataBase Explorer e expanda os objetos para a conexão Cadastro.mdf.

- Selecione a opção Table e clique com o botão direito do mouse selecionando a opção Add New Table

 

A seguir informe, conforme a figura abaixo, os nomes dos campos e o tipo de dados. Ao terminar, salve o trabalho. Retornando a janela DataBase Explorer veremos a tabela Clientes e seus respectivos campos criados.

Se desejar pode incluir valores diretamente na tabela. Para isto clique sobre a tabela Clientes e selecione a opção Show Data Table e digite alguns valores conforme abaixo:

Incluindo a coluna para armazenar a imagem

Vamos incluir na tabela Clientes um campo para poder armazenar a imagem.

Clique com o botão direito do mouse sobre o nome da tabela no DataBase Explorer e selecione Open Table Definition

A seguir inclua uma nova coluna com o nome Foto e o data type igual a image

Criando a Stored Procedure

Vamos criar uma stored procedure que terá o papel de atualizar o campo Foto com a imagem selecionada para cada cliente.

Abra o DataBase Explorer e clique com o botão direito do mouse sobre o item Stored Procedures selecionando a opção Add New Stored Procedure. A seguir digite o código da stored procedure na janela de código conforme abaixo, ao terminar salve o seu trabalho.

Você acabou de criar uma stored procedure chamada spCarregaFoto que trabalha com dois parâmetros : Codigo do tipo integer e Image do tipo Image. A instrução SQL usada UPDATE/SET atualiza o campo foto com a imagem selecionada para um determinado código de cliente.

Criando a interface do formulário

Vamos agora criar a interface gráfica para o formulário onde serão exibidos os dados dos Clientes incluindo agora a foto.

A primeira coisa a fazer é criar no formulário um menu com as opções básicas : inclui, alterar,excluir, salvar, procurar e sair.

Vamos incluir um componente ToolStrip a partir da ToolBox. Este componente é equivalente ao antigo ToolBar, mas, é muito mais fácil de usar. Ao incluir o componente no formulário basta clicar sobre o mesmo e selecionar o tipo de controle que vamos incluir no container. Estarei incluindo componentes do tipo Button.

Feito isto basta selecionar o botão, abrir sua janela de propriedades e clicar na propriedade Image.

A janela Select Resource irá surgir na tela , marque a opção Project resource file e clique no botão Import...     

A seguir basta selecionar uma imagem para incluir no botão e clicar no botão OK.

Após a inclusão de todas as imagens no controle ToolStrip vamos incluir os controles Label e TextBox para cada campo da tabela sendo que teremos que incluir um controle PictureBox para exibir a foto. Além disto temos que incluir quatro botões de comando para efetuar a navegação pelos registros.

Após incluir todos os controles conforme indicado o resultado deverá ser parecido com a tela abaixo:

Vamos agora ao código do projeto:

Os espaços de nomes (namespaces) usados no projeto são:

Imports System.Data.SqlClient
Imports
System.io

As variáveis objetos usadas no projeto são :

Dim conClientes As New SqlConnection()
'Declaramos um objeto Command
Dim cmdClientes As New SqlCommand()
'Declaramos um objeto Data Adapter
Dim daClientes As New SqlDataAdapter()
'Um DataSet
Dim dsClientes As New DataSet()
'O objeto Command Builder
Dim cbClientes As New SqlCommandBuilder()

O código do evento Load do formulário principal é dado a seguir:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Iniciar()
CarregarImagem(txtCodigo.Text)

End Sub

O código da rotina Iniciar() é o seguinte :

Private Sub Iniciar()

Try

'cria uma conexão usando a string de conexao gravada em My.Settings

conClientes = New SqlConnection(My.Settings.conSQL)

'define a instrução SQL para selecionar todas os clientes da tabela Clientes

cmdClientes = New SqlCommand("SELECT codigo,nome,endereco,cidade,estado,pais,email,nascimento,comentarios,foto FROM Clientes", conClientes)

'preenche o DataAdatper, cria o dataset e o commandbuilder

daClientes = New SqlDataAdapter(cmdClientes)

Clientes"

dsClientes = New DataSet()

cbClientes = New SqlCommandBuilder(daClientes)


 
With conClientes

   'Verificamos o estado da conexão

   If .State = ConnectionState.Open Then 'se esta aberta

     .Close() 'fechamos

   End If

   .Open() ' abrimos a conexão

 End With

  'Carrega o DataSet com os dados da tabela

  daClientes.Fill(dsClientes, "Clientes")

  'Efetua a vinculacao via databindings dos campos do formulario com os dados

  vincula()

Catch ex As Exception

  'ocorreu um erro

   MessageBox.Show(ex.Message, "Informacão do Sistema", MessageBoxButtons.OK, MessageBoxIcon.Error)

End Try

End Sub

A rotina vincula() possui o seguinte código:

Private Sub vincula()

  'efetua a vinculação via databindings dos campos com os valores da tabela Clientes

  txtCodigo.DataBindings.Add("Text", dsClientes, "Clientes.Codigo")

  txtNome.DataBindings.Add("Text", dsClientes, "Clientes.Nome")

  txtEndereco.DataBindings.Add("Text", dsClientes, "Clientes.Endereco")

  txtCidade.DataBindings.Add("Text", dsClientes, "Clientes.Cidade")

  txtEstado.DataBindings.Add("Text", dsClientes, "Clientes.Estado")

  txtPais.DataBindings.Add("Text", dsClientes, "Clientes.Pais")

  txtEmail.DataBindings.Add("Text", dsClientes, "Clientes.Email")

  txtNascimento.DataBindings.Add("Text", dsClientes, "Clientes.Nascimento")

  txtComentarios.DataBindings.Add("Text", dsClientes, "Clientes.Comentarios")

End Sub

A rotina carregaImagem() usa o seguinte código :

Private Sub CarregarImagem(ByVal codCliente As Integer)

Try

'Carregar a foto

Dim cmdFoto As New SqlCommand("select Foto from Clientes where codigo = " & codCliente)

cmdFoto.Connection = conClientes

cmdFoto.CommandType = CommandType.Text

Dim daFoto As New SqlDataAdapter(cmdFoto)

Dim dsFoto As New DataSet()
 

daFoto.Fill(dsFoto)


Dim
bits As Byte() = CType(dsFoto.Tables(0).Rows(0).Item(0), Byte())

Dim memorybits As New MemoryStream(bits)

Dim bitmap As New Bitmap(memorybits)


picFoto.Image = bitmap

cmdFoto.Dispose()

dsFoto.Dispose()

cmdFoto.Dispose()

Catch EX As Exception

'se não houver fotos gravadas irá ocorrer um erro que deve ser ignorado

'MessageBox.Show(EX.Message, "Não é possível exibir a foto", MessageBoxButtons.OK, MessageBoxIcon.Information)

picFoto.Image = Nothing

picFoto.Refresh()

End Try

End Sub

A rotina mais importante é a rotina GravarImagem é ela que obtêm os parâmetros da seleção do usuário e usa a stored procedure existente para gravar a imagem na tabela Clientes:

Private Function GravarImagem(ByVal codigoCliente As Integer) As Boolean

        'Define variaveis para gravar a imagem
        Dim SalvaImagem As Boolean = False
        Dim nomeArquivo As String = ""
        Try
            'buscamos a imagem a ser gravada
            Dim openDlg As OpenFileDialog = New OpenFileDialog()
            openDlg.Filter = "All Bitmap files|*.bmp"
            Dim filter As String = openDlg.Filter
            openDlg.Title = "Abrir Arq. BitMap"
            'abre a janela de diáglogo para procurar o arquivo a ser usado como imagem
            If (openDlg.ShowDialog() = Windows.Forms.DialogResult.OK) Then
                nomeArquivo = openDlg.FileName
                SalvaImagem = True
            Else
                Return False
                Exit Function
            End If
            'se uma imagem foi selecionada então inicia a gravação        
            If SalvaImagem = True Then
                'Carrega a foto
                Dim fsFoto As FileStream
                fsFoto = New FileStream(nomeArquivo, FileMode.Open)

                Dim fiFoto As FileInfo = New FileInfo(nomeArquivo)
                Dim Temp As Long = fiFoto.Length
                Dim lung As Long = Convert.ToInt32(Temp)
                Dim picture(lung) As Byte
                'le a imagem
                fsFoto.Read(picture, 0, lung)
                fsFoto.Close()
                'cria um novo objeto command usando a stored procedure ja criada na base de dados
                Dim cmdFoto As New SqlCommand("spCarregaFoto", conClientes)
                cmdFoto.CommandType = CommandType.StoredProcedure
                'recebe os parametros para a stored procedure spCarregaFoto
                Dim sql_codigoCliente = New SqlParameter("@CODIGO", codigoCliente)
                Dim sql_Foto As New SqlParameter("@IMAGEM", SqlDbType.Image)

                sql_Foto.Value = picture
                'adicona os parametros informados
                cmdFoto.Parameters.Add(sql_codigoCliente)
                cmdFoto.Parameters.Add(sql_Foto)
                'executa a stored procedures usando os parâmetros informados
                cmdFoto.ExecuteNonQuery()
                cmdFoto.Dispose()

                sql_FOTO = Nothing
                picture = Nothing
                Return True
                Exit Function
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Return False
        End Try
    End Function

 

O código usado para acionar uma rotina quando o usuário clica em uma opção do menu é o seguinte:

Private Sub toolStripMenu_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) 
Handles toolStripMenu.ItemClicked
        Select Case toolStripMenu.Items.IndexOf(e.ClickedItem)
            Case Is = 0
                'novo registro
                NovoRegistro()
            Case Is = 1
                'Modificar
                atualizar()
                CarregarImagem(CType(txtCodigo.Text, Integer))
            Case Is = 2
                'excluir
                Eliminar()
            Case Is = 3
                'gravar
                Gravar()
                If txtCodigo.Text <> "" Then
                    CarregarImagem(CType(txtCodigo.Text, Integer))
                End If
            Case Is = 4
                'cancelar 
                Cancelar()
                CarregarImagem(CType(txtCodigo.Text, Integer))
            Case Is = 5
                'Buscar registro
                Me.BindingContext(dsClientes, "Clientes").Position = BuscarRegistro(Me.BindingContext(dsClientes, "Clientes").Position)
                CarregarImagem(CType(txtCodigo.Text, Integer))
            Case Is = 7
                'encerrar
                If (MessageBox.Show("Confirma encerramento do programa ? ", "Encerrar", MessageBoxButtons.YesNo) = _ 
Windows.Forms.DialogResult.Yes) Then
                    Me.Close()
                End If
        End Select
    End Sub

 

O código para a rotina buscarRegistro é o seguinte:

Private Function BuscarRegistro(ByVal posCliente As Integer) As Integer
        'Código para buscar un registro
        'Recebe como parâmetro a posição atual no DataSet
        'de forma que se não localizar o registro solicitado possa voltar ao registro
        'no qual estava antes de iniciar a busca
        Try
            Dim dvClientes As DataView = New DataView(dsClientes.Tables(0), "", "Codigo", DataViewRowState.CurrentRows)
            Dim codigo_Cliente As Integer = 0
            'Solicitamos o codigo do cliente para efetuar a busca
            codigo_Cliente = InputBox("Innforme o Codigo a procurar", "Buscar")
            If Not codigo_Cliente = 0 Then
                'Retornamos o indice do cliente encontrado
                Return dvClientes.Find(codigo_Cliente)
                Exit Function
            Else
                'Se não especificou o cliente retornamos a posição do cliente original(posCliente)
                MessageBox.Show("A busca não pode ser realizada", "Informação do sistema", MessageBoxButtons.OK, _ 
MessageBoxIcon.Information)
                Return posCliente
                Exit Function
            End If
        Catch ex As Exception
            'Se não encontrou o cliente retorna a posição original do cliente(posCliente)
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Return posCliente
            Exit Function
        End Try
    End Function

 

As rotinas Gravar, NovoRegistro,Eliminar e Cancelar são exibidas a seguir. Não me preocupei muito com suas funcionalidades visto que o foco do artigo é gravar e recuperar a imagem do banco de dados.

Private Sub Gravar()

Try

'Termina a edição atual

Me.BindingContext(dsClientes, "Clientes").EndCurrentEdit()

'Atualiza a base de dados

daClientes.Update(dsClientes, "Clientes")

Catch ex As Exception

MsgBox(ex.Source & "; " & ex.Message, MsgBoxStyle.OkOnly, "Ocorreu um erro durante a gravação.")

End Try

End Sub

 

Private Sub NovoRegistro()

Try

'Termina a edicao atual

Me.BindingContext(dsClientes, "Clientes").EndCurrentEdit()

picFoto.Image = Nothing

picFoto.Refresh()

Me.txtNome.Focus()

'Prepara o DataSet para aceitar um novo registro

Me.BindingContext(dsClientes, "Clientes").AddNew()

Catch ex As Exception

MsgBox(ex.Source & "; " & ex.Message)

End Try

End Sub

 

Private Sub Eliminar()

'Obtemos a posição atual e eliminamos o registro que esta nesta posição

'Outra forma seria usar uma instrução SQL - DELETE/FROM

Dim Resp As String

Try

Resp = MsgBox("Confirma a exclusão do registro ? " & vbCrLf & "Nota: Eliminar registros pode prejudicar " & " a execução.", MsgBoxStyle.OkCancel, "Eliminar Registro")

If Resp = vbOK Then

Dim Registro As Integer

Registro = Me.BindingContext(dsClientes, "Clientes").Position

Me.BindingContext(dsClientes, "Clientes").EndCurrentEdit()

Me.BindingContext(dsClientes, "Clientes").RemoveAt(Registro)

daClientes.Update(dsClientes, "Clientes")

Me.BindingContext(dsClientes, "Clientes").Position = 0

End If

Catch ex As Exception

MsgBox(ex.Source & "; " & ex.Message, MsgBoxStyle.OkOnly, "Ocorreu um erro")

End Try

End Sub

Private Sub Cancelar()

Try

'Cancela operacao

Me.BindingContext(dsClientes, "Clientes").CancelCurrentEdit()

Catch ex As Exception

MsgBox(ex.Source & "; " & ex.Message, MsgBoxStyle.OkOnly, "Ocorreu um erro")

End Try

End Sub

Os códigos para cada um dos botões que permitem a navegação pelos registros são mostrados abaixo.

Private Sub btnPrimeiro_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrimeiro.Click

Me.BindingContext(dsClientes, "Clientes").Position = 0

CarregarImagem(txtCodigo.Text)

End Sub
 

Private Sub btnAnterior_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAnterior.Click

Me.BindingContext(dsClientes, "Clientes").Position -= 1

CarregarImagem(txtCodigo.Text)

End Sub
 

Private Sub btnProximo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProximo.Click

Me.BindingContext(dsClientes, "Clientes").Position += 1

CarregarImagem(CType(txtCodigo.Text, Integer))

End Sub
 

Private Sub btnUltimo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUltimo.Click

Me.BindingContext(dsClientes, "Clientes").Position = Me.BindingContext(dsClientes, "Clientes").Count - 1

CarregarImagem(txtCodigo.Text)

End Sub

 

Finalmente o código relacionado ao evento Click do botão - Incluir Foto - é dado a seguir:

Private Sub btnFoto_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFoto.Click

If GravarImagem(txtCodigo.Text) Then

   MessageBox.Show("Imagem armazenada", "Gravar Imagem", MessageBoxButtons.OK, MessageBoxIcon.Information)

   CarregarImagem(txtCodigo.Text)

End If

End Sub

No código acima estamos chamando a função GravarImagem passando o código do cliente como parâmetro.

Ao executar o projeto o usuário deverá gravar um registro e em seguida incluir a foto para o mesmo via botão - Incluir Foto. Abaixo temos uma tela de exemplo da aplicação em execução:

Como vimos é muito simples gravar e recuperar imagens em um banco de dados SQL Server.

Bom estudo e até o próximo artigo VB.NET...


José Carlos Macoratti

1