VB
.NET - Acessando um banco de dados Access (CRUD) - II
Na primeira parte deste artigo eu crie uma aplicação VB .NET para realizar a manutenção em uma tabela Alunos do banco de dados Escola.mdb.
Assim criamos o banco de dados Escola.mdb e a tabela Alunos e a seguir criamos o projeto no VB .NET 2010 Express onde definimos as operações para incluir, alterar, excluir e consultar registros na tabela Alunos.
Concluímos e testamos o projeto e esta tudo funcionando sem problemas.
O que vamos então fazer neste artigo ?
Embora nossa aplicação esteja funcional ele pode ser melhorada para ser mais fácil de manter e de estender.
Como assim ???
Quando criamos nossa aplicação definimos na camada de apresentação, no caso o formulário form1.vb, todas as operações nos eventos dos botões de comando.
![]() |
Assim usamos o código para acessar e para apresentar os dados em um único lugar: a camada de apresentação.
Se você analisar o código usado irá notar que usamos referências aos namespaces System.Data e System.Data.Oledb no formulário e que no código usado criamos instâncias de objetos ADO .NET como Connection, Command, DataTable, DataAdatper também no formulário. Além disso definimos os comandos SQL para selecionar, incluir, alterar e excluir também no formulário.
Temos também código duplicado no formulário, principalmente na definição da string de conexão, que esta sendo definida em cada evento Click dos botões Novo,Deletar, Alterar e Procurar.
Dessa forma nosso formulário além de código duplicado também possui mesclado o código de apresentação e o código de acesso a dados e isso não é uma boa prática.
Por quê ?
Porque qualquer alteração relacionada com o acesso aos dados implicará em alterar também a camada de apresentação. A criação de um novo campo, por exemplo, faria com que o formulário form1.vb fosse todo alterado pois nele esta contido toda a lógica de acesso aos dados.
Se a string e conexão for alterada também teremos que alterar o código em todo o formulário.
Vamos então separar as responsabilidades e remover do formulário todo o código e referência relacionada com o acesso aos dados criando uma camada de acesso a dados que será responsável conhecer, acessar, e retornar as informações dos dados.
Nosso formulário form1.vb deverá unicamente chamar a camada de acesso a dados e apresentar o resultado ao usuário.
Além disso vamos definir a string de conexão em um único lugar na aplicação que será o arquivo de configuração App.Config. Para obter a string de conexão iremos acessar e recuperar a string de conexão deste arquivo. Assim se houver qualquer mudança na string de conexão teremos que alterar somente em único local o seu valor.
Criando a infraestrutura da camada de acesso aos dados
Abra o projeto original CadastroAlunosAccess onde teremos apenas o formulário form1.vb. Vamos criar a infraestrutura para podermos criar a nossa camada de acesso aos dados
1- Referenciando o namespace System.Configuration
No menu Project, clique em Add Reference e na janela Add Reference clique na guia .NET e selecione System.Configuration e clique em OK;
![]() |
2- Criando o arquivo de configuração App.Config
No menu Project clique em Add New Item e selecione o template Application Configuration FIle aceitando o nome padrão app.config e clique em Add;
![]() |
3- Definindo a string e conexão no arquivo app.config
Abra o arquivo app.config criado e inclua o código destacado em azul abaixo neste arquivo:
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="ConexaoEscolaMDB" providerName="System.Data.OleDb" connectionString="Provider=Microsoft.Jet.OleDb.4.0; Data Source=C:\dados\Escola.mdb"/> </connectionStrings> <system.diagnostics> ........ |
Definimos no arquivo a string de conexão com o banco de dados identificada pelo nome ConexaoEscolaMDB.
4- Criando a classe Aluno
No menu Project, Clique em Add Class, informe o nome Aluno.vb e clique no botão Add;
A seguir defina o código abaixo na classe Aluno:
Public
Class
Aluno Public Property Codigo As Integer Public Property Nome As String Public Property Imagem As Image End Class |
A classe Aluno representa um aluno e possui 3 propriedades que possuem nomes idênticos aos campos da tabela Alunos.
Usamos essa classe para realizar a comunicação entre as camadas de acesso a dados e a camada de apresentação. Podemos dizer que essa classe é um DTO - Data Transfer Object.
Criando a camada de apresentação
Volte ao menu Project, clique em Add Class e informe o nome AcessoDados.vb clicando a seguir no botão Add para criar a classe AcessoDados;
Defina os seguintes namespaces neste arquivo:
Imports
System.DataE a seguir, logo após a declaração da classe vamos definir os objetos ADO .NET:
Dim Da As New OleDbDataAdapterAgora podemos iniciar a criação dos métodos da classe AcessoDados que irão acessar e persistir os dados na tabela Alunos.
1- Método getConexaoDB() - obtém a string de conexão do arquivo app.config, abre e retorna uma conexão do tipo OledbConnection;
Public Function getConexaoDB() As OleDbConnection Try cn.ConnectionString = ConfigurationManager.ConnectionStrings("ConexaoEscolaMDB").ConnectionString cn.Open() Return cn Catch ex As Exception Throw ex End Try End Function |
2- Método closeConexaoDB() - Fecha uma conexão aberta
Public Sub closeConexaoDB(ByVal cn As OleDbConnection) Try If cn.State = ConnectionState.Open Then cn.Close() End If Catch ex As Exception Throw ex End Try End Sub |
3- Método incluirDados() - Inclui um novo aluno na tabela alunos usando o comando SQL INSERT INTO;
Public Sub incluirDados(ByVal nome As String, ByVal arrImage() As Byte, ByVal strImage As String) Try cn = getConexaoDB() Cmd.Connection = cn Cmd.CommandText = "INSERT INTO Alunos(nome, imagem) " & _ "VALUES( '" & nome & "'," & strImage & ")" If strImage = "?" Then Cmd.Parameters.Add(strImage, OleDb.OleDbType.Binary).Value = arrImage End If Cmd.ExecuteNonQuery() Catch ex As Exception Throw ex Finally closeConexaoDB(cn) End Try End Sub |
4- Método procurarDados() - seleciona um aluno pelo código e retorna um objeto Aluno.
Public Function procurarDados(ByVal codigo As Integer) As Aluno Dim aluno As New Aluno Try cn = getConexaoDB() Dim da As New OleDb.OleDbDataAdapter("SELECT * FROM Alunos " & " WHERE codigo=" & codigo, cn) Dim dt As New DataTable Dim arrImage() As Byte = Nothing Dim myMS As New IO.MemoryStream da.Fill(dt) If dt.Rows.Count > 0 Then aluno.Codigo = dt.Rows(0).Item("codigo") aluno.Nome = dt.Rows(0).Item("nome") & "" If Not IsDBNull(dt.Rows(0).Item("imagem")) Then arrImage = dt.Rows(0).Item("imagem") For Each ar As Byte In arrImage myMS.WriteByte(ar) Next aluno.Imagem = System.Drawing.Image.FromStream(myMS) Else aluno.Imagem = Nothing End If Else aluno = Nothing End If Catch ex As Exception Throw ex Finally closeConexaoDB(cn) End Try Return Aluno End Function |
5- Método carregaDados() - Seleciona todos os alunos e retorna um DataTable.
Public Function carregaDados() As DataTable Dt = New DataTable cn = getConexaoDB() Try With Cmd .CommandType = CommandType.Text .CommandText = "SELECT * from Alunos" .Connection = cn End With With Da .SelectCommand = Cmd .Fill(Dt) End With Catch ex As Exception Dt = Nothing Finally closeConexaoDB(cn) End Try Return Dt End Function |
6- Método deletarRegistro() - exclui um aluno pelo código da tabela Alunos.
Public Sub deletarRegistro(ByVal codigo As Integer) Try cn = getConexaoDB() Dim myCmd As New OleDb.OleDbCommand myCmd.Connection = cn myCmd.CommandText = "DELETE FROM Alunos WHERE codigo = " & codigo myCmd.ExecuteNonQuery() Catch ex As Exception Throw ex Finally closeConexaoDB(cn) End Try End Sub |
7- Método atualizarDados() - Atualiza os dados de um aluno selecionado pelo código.
Public Sub atualizarDados(ByVal nome As String, strImagem As String, codigo As Integer, arrImagem() As Byte) Try cn = getConexaoDB() Dim myCmd As New OleDb.OleDbCommand myCmd.Connection = cn myCmd.CommandText = "Update Alunos SET nome = '" & nome & "'," & "imagem = " & strImagem & " WHERE codigo =" & codigo If strImagem = "?" Then myCmd.Parameters.Add(strImagem, OleDb.OleDbType.Binary).Value = arrImagem End If myCmd.ExecuteNonQuery() Catch ex As Exception Throw ex Finally closeConexaoDB(cn) End Try End Sub |
Note que em todos os métodos usamos o tratamento de erros Try/Catch/Finally onde o código do bloco Finally sempre será executado.
Alterando a camada de apresentação
Agora que temos uma camada de acesso aos dados criada e pronta para o uso vamos alterar o código do formulário form1.vb removendo toda a referência e código de acesso aos dados.
Vou mostrar a esquerda o código anterior usado e à esquerda no novo código que usa a nossa camada de acesso aos dados.
Remova as referências a System.Data e System.Data.OleDb do formulário.
Vamos criar uma instância da classe AcessoDados logo após a declaração do formulário:
Dim acc As New AcessoDadosNo evento Load do formulário que ocorre quando a aplicação for aberta vamos continuar a usar o código que chama a rotina CarregaDados();
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load CarregaDados() End Sub |
A rotina CarregaDados() vai acessar o banco de dados e selecionar todas as informações existentes e exibi-las no controle DataGridView no formulário form1;
Abaixo vemos à esquerda como era a rotina e à direita como ficou o novo código:
Note que estamos usando o objeto acc que é uma instância da classe AcessoDados e estamos chamando o método carregaDados()
Private Sub CarregaDados() Dim cn As New OleDb.OleDbConnection cn.ConnectionString = "Provider=Microsoft.Jet.OleDb.4.0; Data Source=c:\dados\Escola.mdb" cn.Open() Try With Cmd .CommandType = CommandType.Text .CommandText = "SELECT * from Alunos" .Connection = cn End With With Da .SelectCommand = Cmd Dt = New DataTable .Fill(Dt) dgvAlunos.DataSource = Dt End With Catch ex As Exception MsgBox(ex.Message) End Try End Sub |
Try dgvAlunos.DataSource = acc.carregaDados() Catch ex As Exception MsgBox(ex.Message) End Try
|
A seguir temos o código do evento Click do botão Incluir que acessa o banco de dados, abre uma conexão e inclui um novo registro na tabela Alunos usando uma instrução SQL INSERT INTO;
Á direita o código antigo e a esquerda o novo código onde chamamos o método incluirDados() da classe AcessoDados:
Private Sub btnIncluir_Click(sender As System.Object, e As System.EventArgs) Handles btnIncluir.Click Dim cn As New OleDb.OleDbConnection cn.ConnectionString = "Provider=Microsoft.Jet.OleDb.4.0; Data Source=c:\dados\Escola.mdb" cn.Open() Dim arrImagem() As Byte Dim strImagem As String Dim ms As New IO.MemoryStream If txtNome.Text = String.Empty Then MsgBox("Informe o nome do aluno") txtNome.Focus() Return End If ' If Not IsNothing(Me.picFoto.Image) Then Me.picFoto.Image.Save(ms, Me.picFoto.Image.RawFormat) arrImagem = ms.GetBuffer strImagem = "?" Else arrImagem = Nothing strImagem = "NULL" End If Dim myCmd As New OleDb.OleDbCommand myCmd.Connection = cn myCmd.CommandText = "INSERT INTO Alunos(nome, imagem) " & _ " VALUES( '" & Me.txtNome.Text & "'," & strImagem & ")" If strImagem = "?" Then myCmd.Parameters.Add(strImagem, OleDb.OleDbType.Binary).Value = arrImagem End If myCmd.ExecuteNonQuery() MsgBox("Dados Salvos com sucesso!") cn.Close() CarregaDados() End Sub |
Private Sub btnIncluir_Click(sender As System.Object, e As System.EventArgs) Handles btnIncluir.Click Dim arrImage() As Byte Dim strImage As String Dim myMs As New IO.MemoryStream If txtNome.Text = String.Empty Then MsgBox("Informe o nome do aluno") txtNome.Focus() Return End If If Not IsNothing(Me.picFoto.Image) Then Me.picFoto.Image.Save(myMs, Me.picFoto.Image.RawFormat) arrImage = myMs.GetBuffer strImage = "?" Else arrImage = Nothing strImage = "NULL" End If Try acc.incluirDados(txtNome.Text, arrImage, strImage) MsgBox("Dados Salvos com sucesso!") Catch ex As Exception MsgBox("Erro ao incluir dados!") End Try CarregaDados() End Sub
|
No evento Click do botão de comando Procurar o código abaixo chama a rotina Procurar();
Aqui não houve alteração.
Private Sub btnProcurar_Click(sender As System.Object, e As System.EventArgs) Handles btnProcurar.Click If txtCodigo.Text = String.Empty Then MsgBox("Informe o codigo do aluno") Else Procurar(Me.txtCodigo.Text) End If End Sub |
A rotina Procurar() recebe o código do aluno, abre a conexão com o banco de dados e seleciona o aluno pelo seu código preenchendo um DataTable e populando os controles do formulário com os dados obtidos;
O novo código à direita chama o método procurarDados() e preenche um objeto aluno exibindo os dados no formulário:
Private Sub Procurar(ByVal codigo As Integer) Dim cn As New OleDb.OleDbConnection cn.ConnectionString = "Provider=Microsoft.Jet.OleDb.4.0; Data Source=c:\dados\Escola.mdb" cn.Open() Dim arrImagem() As Byte Dim ms As New IO.MemoryStream Dim da As New OleDb.OleDbDataAdapter("SELECT * FROM Alunos " & _ " WHERE codigo=" & codigo, cn) Dim dt As New DataTable da.Fill(dt) If dt.Rows.Count > 0 Then Me.txtCodigo.Text = dt.Rows(0).Item("codigo") Me.txtNome.Text = dt.Rows(0).Item("nome") & "" If Not IsDBNull(dt.Rows(0).Item("imagem")) Then arrImagem = dt.Rows(0).Item("imagem") For Each ar As Byte In arrImagem ms.WriteByte(ar) Next ' Me.picFoto.Image = System.Drawing.Image.FromStream(ms) Else Me.picFoto.Image = _ System.Drawing.Image.FromFile(Application.StartupPath & "/semfoto.jpg") End If Me.btnIncluir.Enabled = False Else MsgBox("Registro não localizado") End If cn.Close() End Sub |
Private Sub Procurar(ByVal codigo As Integer) Dim arrImage() As Byte = Nothing Dim myMS As New IO.MemoryStream Dim aluno1 As New Aluno aluno1 = acc.procurarDados(codigo) If Not IsNothing(aluno1) Then Me.txtCodigo.Text = aluno1.Codigo Me.txtNome.Text = aluno1.Nome If Not IsDBNull(aluno1.Imagem) Then Me.picFoto.Image = aluno1.Imagem Else Me.picFoto.Image = _ System.Drawing.Image.FromFile(Application.StartupPath & "/semfoto.jpg") End If Me.btnIncluir.Enabled = False Else MsgBox("Registro não localizado") End If End Sub
|
No evento Click do controle LinkLabel o código abre uma caixa de diálogo para que uma imagem seja selecionada e exibida no controle Image;
Aqui não houve alteração no código:
Private Sub lnkProcurar_LinkClicked(sender As System.Object, e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles lnkProcurar.LinkClicked If Me.ofdImagem.ShowDialog = 1 Then Me.picFoto.Image = System.Drawing.Image.FromFile(Me.ofdImagem.FileName) Else Me.picFoto.Image = System.Drawing.Image.FromFile(Application.StartupPath & "/semfoto.jpg") End If End Sub |
No evento CellClick do controle DataGridView quando o usuário clicar em um célula do controle iremos selecionar o código da célula clicada e chamar a rotina Procurar passando este código;
Aqui não houve alteração no código:
Private Sub dgvAlunos_CellClick(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvAlunos.CellClick Try 'Dim codigo As Integer = dgvAlunos.Rows(e.RowIndex).Cells(e.ColumnIndex).Value() Dim codigo As Integer = dgvAlunos.Rows(e.RowIndex).Cells(0).Value() Procurar(codigo) Catch ex As Exception MsgBox("Seleção Inválida. Clique em uma célula com dados.") End Try End Sub |
No evento Click do botão Limpar limpamos os controles do formulário;
Aqui não houve alteração no código:
Private Sub btnLimpar_Click(sender As System.Object, e As System.EventArgs) Handles btnLimpar.Click Me.txtCodigo.Text = "" Me.txtNome.Text = "" Me.picFoto.Image = Nothing Me.txtCodigo.Focus() Me.btnIncluir.Enabled = True End Sub |
O evento Click do botão Deletar será solicitada uma confirmação para excluir o registro selecionado; a seguir será aberta uma conexão com o banco de dados e o registro selecionado será deletado usando a instrução SQL DELETE FROM;
O novo código à direita chama o método deletarRegistro():
Private Sub btnDeletar_Click(sender As System.Object, e As System.EventArgs) Handles btnDeletar.Click Dim resultado As DialogResult = MessageBox.Show("Confirma a exclusão deste registro ?", _ "Excluir", MessageBoxButtons.YesNo, MessageBoxIcon.Question) If resultado = vbYes Then Dim cn As New OleDb.OleDbConnection cn.ConnectionString = "Provider=Microsoft.Jet.OleDb.4.0; Data Source=c:\dados\Escola.mdb" cn.Open() If txtCodigo.Text = String.Empty Then MsgBox("Informe o codigo do aluno") txtNome.Focus() Return End If Dim myCmd As New OleDb.OleDbCommand myCmd.Connection = cn myCmd.CommandText = "DELETE FROM Alunos WHERE codigo = " & txtCodigo.Text myCmd.ExecuteNonQuery() MsgBox("Dados excluídos com sucesso!") cn.Close() CarregaDados() End If End Sub |
Private Sub btnDeletar_Click(sender As System.Object, e As System.EventArgs) Handles btnDeletar.Click Dim resultado As DialogResult = MessageBox.Show("Confirma a exclusão deste registro ?", _ "Excluir", MessageBoxButtons.YesNo, MessageBoxIcon.Question) If resultado = vbYes Then Dim codigo As Integer If txtCodigo.Text = String.Empty Then MsgBox("Informe o codigo do aluno") txtNome.Focus() Return Else codigo = Convert.ToInt32(txtCodigo.Text) End If Try acc.deletarRegistro(codigo) MsgBox("Dados excluídos com sucesso!") Catch ex As Exception MsgBox(ex.Message) End Try CarregaDados() End If End Sub
|
No evento Click do botão Alterar abrimos uma conexão com o banco de dados e alteramos as informações do registro selecionado usando a instrução SQL UPDATE/SET;
Private Sub btnAlterar_Click(sender As System.Object, e As System.EventArgs) Handles btnAlterar.Click Dim cn As New OleDb.OleDbConnection cn.ConnectionString = "Provider=Microsoft.Jet.OleDb.4.0; Data Source=c:\dados\Escola.mdb" cn.Open() Dim arrImagem() As Byte Dim strImagem As String Dim ms As New IO.MemoryStream If txtNome.Text = String.Empty Then MsgBox("Informe o nome do aluno") txtNome.Focus() Return End If ' If Not IsNothing(Me.picFoto.Image) Then Me.picFoto.Image.Save(ms, Me.picFoto.Image.RawFormat) arrImagem = ms.GetBuffer strImagem = "?" Else arrImagem = Nothing strImagem = "NULL" End If Dim myCmd As New OleDb.OleDbCommand myCmd.Connection = cn myCmd.CommandText = "Update Alunos SET nome = '" & txtNome.Text & "'," & "imagem = " & strImagem & " WHERE codigo =" & txtCodigo.Text If strImagem = "?" Then myCmd.Parameters.Add(strImagem, OleDb.OleDbType.Binary).Value = arrImagem End If myCmd.ExecuteNonQuery() MsgBox("Dados Alterados com sucesso!") cn.Close() CarregaDados() End Sub |
Código anterior |
Abaixo o novo código que chama o método atualizarDados():
Private Sub btnAlterar_Click(sender As System.Object, e As System.EventArgs) Handles btnAlterar.Click Dim arrImage() As Byte Dim strImage As String Dim myMs As New IO.MemoryStream If txtNome.Text = String.Empty Then MsgBox("Informe o nome do aluno") txtNome.Focus() Return End If If Not IsNothing(Me.picFoto.Image) Then Me.picFoto.Image.Save(myMs, Me.picFoto.Image.RawFormat) arrImage = myMs.GetBuffer strImage = "?" Else arrImage = Nothing strImage = "NULL" End If Try acc.atualizarDados(txtNome.Text, strImage, txtCodigo.Text, arrImage) MsgBox("Dados Alterados com sucesso!") Catch ex As Exception MsgBox(ex.Message) End Try CarregaDados() End Sub
|
No evento Validating da caixa de texto txtNome usamos o controle ErrorProvider para validar o campo txtNome;
Aqui não houve alteração de código:
Private Sub txtNome_Validating(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles txtNome.Validating If (txtNome.Text.Trim().Length = 0) Then erro.SetError(txtNome, "Informe o nome do aluno") Else erro.SetError(txtNome, "") End If End Sub |
Executando a solução teremos a exibição do formulário conforme mostra a figura abaixo obtendo assim o mesmo resultado final:
![]() |
Dessa forma criamos uma camada de acesso a dados e aplicamos uma das principais regras das boas práticas : a separação de responsabilidades.
Podemos melhorar ainda mais nossa aplicação usando um ORM como o Entity Framework para remover todas as referências aos objetos ADO .NET e os comandos SQL e trabalhar somente com objetos.
Pegue o projeto completo
aqui:
CadastroAlunosAccess_CamadaAcessoDados.zip
Aguarde que em outro artigo eu vou mostrar como usar o Entity Framework e realizar o mapeamento ORM abstraindo assim os objetos ADO .NET e os comandos SQL.
Heb 2:17
Pelo que convinha que em tudo fosse feito semelhante a seus irmãos, para se tornar um sumo sacerdote misericordioso e fiel nas coisas concernentes a Deus, a fim de fazer propiciação pelos pecados do povo.Heb 2:18
Porque naquilo que ele mesmo, sendo tentado, padeceu, pode socorrer aos que são tentados.
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências: