Banco de dados: Programando com Classe(s)
A utilização dos módulos de classe na programação torna o nosso código mais elegante. Ao usar a técnica de encapsular nosso código , estamos isolando código complexo do resto da aplicação e somente expondo os métodos , propriedades e eventos. Nisto está as bases da criação dos controles ActiveX e da criação dos componentes reutilizáveis.
A programação com banco de dados é grandemente afetada pela utilização dos módulos de classe. Se você já teve que escrever complexas consultas SQL para o seu banco de dados , vai perceber que usando classes vai tornar o seu código mais funcional e fácil de manter.
Vamos mostrar em um exemplo simples os fundamentos para a utilização dos módulos de classe ajudando-o assim a dar os primeiros passos nesse terreno que parece mais um campo de areia movediça.
O projeto
Vamos usar o banco de dados Nwind.mdb (esse banco de dados vem com Access) o qual contém as seguintes tabelas que interessam ao nosso objetivo.
Categorias - Categorias das
bebidas
Pedidos - Informação sobre os pedidos
Detalhes do Pedido- Detalhes dos pedidos
Produtos - Relação dos produtos
Fornecedores - Relação dos fornecedores
Obs: Exibimos aqui somentes as tabelas que iremos utilizar.
O relacionamento entre estas tabelas é mostrado a seguir:
Nosso objetivo é extrair informações sobre os fornecedores e qual bebidas eles distribuem .Queremos exibir somente o nome do Fornecedor e o nome da bebida que é distribuida . Por exemplo queremos saber quais bebidas são distribuidos por Exotic Liquidis; no caso , fazendo um consulta iremos descobrir que este fornecedor distribui as seguintes bebidas : : "Chai", "Chang"
Você já percebeu esta informação pode ser extraida usando SQL , porém note que temos três tabelas relacionadas envolvidas na obtenção desta informação. O relacionamento das tabelas que iremos usar para criar a consulta SQL e a consulta que iremos criar no modo estrutura é exibido a seguir:
A consulta SQL usada para o nosso caso usa dois parâmetros que devemos fornecer: o nome do fornecedor(nomedaEmpresa) e o nome da categoria(nomedaCategoria) que desejamos exibir. A seguir o código extraído da consulta montanda no Access :
SELECT
Fornecedores.NomeDaEmpresa, Produtos.NomeDoProduto FROM Fornecedores INNER JOIN (Categorias INNER JOIN Produtos ON Categorias.CódigoDaCategoria = Produtos.CódigoDaCategoria) ON Fornecedores.CódigoDoFornecedor = Produtos.CódigoDoFornecedor WHERE (((Fornecedores.NomeDaEmpresa)=[nomeEmpresa]) AND ((Categorias.NomeDaCategoria)=[nomeCategoria])); |
Você poderia fazer um programa criando uma função em um módulo que recebesse os parâmetros usados e retornasse o resultado de sua consulta ou usar módulo de classes para encapsular o seu código e torná-lo reutilizável.
Vamos lembrar as principais diferenças entre um módulo padrão e um módulo de classe:
Vamos optar por usar um módulo de classe em nosso projeto.
Escrevendo o Módulo de Classe ( Class Module )
Inicie um novo projeto no VB (stantard EXE) , referencie a Microsoft DAO 3.5/3.51 Object Library (menu: Project->References...) no seu projeto e a seguir inclua um módulo de classe (menu : Project->Add a Class Module) . Dê o nome cls_Sql para o módulo de classe e salve o seu projeto com o nome de class_SQL.
Vamos iniciar definindo duas propriedades públicas para a classe e uma váriavel pública para receber as mensagens que o objeto retornará. Insira as linhas de código como abaixo no início do módulo de classe:
Agora vamos definir o método que irá executar a consulta , vamos chamá-lo de , Executa_SQL. Definimos um método incluindo uma procedure no módulo de classe. Veja o código da procedure a seguir:
Sub Executa_SQL() Dim strSQL As String Dim db As Database Dim qdfTemp As QueryDef Dim rsResultado As Recordset 'Constroi a consulta SQL strSQL = "SELECT Fornecedores.NomeDaEmpresa, Produtos.NomeDoProduto " strSQL = strSQL & " FROM Fornecedores INNER JOIN (Categorias INNER JOIN Produtos" strSQL = strSQL & " ON Categorias.CódigoDaCategoria = Produtos.CódigoDaCategoria)" strSQL = strSQL & " ON Fornecedores.CódigoDoFornecedor = Produtos.CódigoDoFornecedor" strSQL = strSQL & " WHERE Fornecedores.NomeDaEmpresa='" & NomedaEmpresa & "'" strSQL = strSQL & " AND Categorias.NomeDaCategoria='" & NomedaCategoria & "'" dbname = "c:\teste\nwind2000.mdb" Set db = OpenDatabase(dbname) Set qdfTemp = db.CreateQueryDef("") qdfTemp.SQL = strSQL Set rsResultado = qdfTemp.OpenRecordset(dbOpenSnapshot) If rsResultado.RecordCount > 0 Then rsResultado.MoveFirst 'Enumerando o recordset With rsResultado Do While Not .EOF strmensagem = strmensagem & .Fields(1) & vbCrLf .MoveNext Loop End With Else strmensagem = "Não há dados para estes parâmetros ! " End If rsResultado.Close qdfTemp.Close End Sub |
Analisando o código:
-Dimensionamos as variáveis objeto para acesso aos dados - db , qdftemp , rsresultado
Dim strSQL As String
Dim db As Database
Dim qdfTemp As QueryDef
Dim rsResultado As Recordset
-Construimos a consulta SQL que irá extrair o resultado com base nos parâmetros : NomedaEmpresa, NomedaCategoria
strSQL = "SELECT Fornecedores.NomeDaEmpresa,
Produtos.NomeDoProduto "
strSQL = strSQL & " FROM Fornecedores INNER JOIN
(Categorias INNER JOIN Produtos"
strSQL = strSQL & " ON Categorias.CódigoDaCategoria =
Produtos.CódigoDaCategoria)"
strSQL = strSQL & " ON Fornecedores.CódigoDoFornecedor
= Produtos.CódigoDoFornecedor"
strSQL = strSQL & " WHERE
Fornecedores.NomeDaEmpresa='" & NomedaEmpresa &
"'"
strSQL = strSQL & " AND
Categorias.NomeDaCategoria='" & NomedaCategoria &
"'"
-Definimos o caminho do banco de dados e a seguir o abrimos:
dbname = "c:\teste\nwind2000.mdb"
Set db = OpenDatabase(dbname)
- Limpamos a querydef e a seguir atribuimos a
nossa consulta SQL para a QueryDef definida. Depois executamos a
consulta para geração de um recordset do tipo snapshot
Set qdfTemp = db.CreateQueryDef("")
qdfTemp.SQL = strSQL
Set rsResultado = qdfTemp.OpenRecordset(dbOpenSnapshot)
-Se a consulta retorna valores , estes são exibidos , caso contrário uma mensagem alerta o usuário de não há dados para os critérios adotados.
Pronto já temos uma classe definida com duas propriedades , os nossos parâmetros e um método , que executa a nossa consulta, só nos resta usá-lo na prática.
Como cada módulo de classe tem um evento Initialize o qual contém código que é executado quando um objeto baseado na classe é criado e um evento Terminate quando o objeto é destruido. O código que será executado quando nosso objeto for destruido será o seguinte:
Private Sub Class_Terminate() MsgBox strmensagem, Title:="Resultado da consulta para - " _ & UCase(NomedaEmpresa), buttons:=vbExclamation End Sub |
Ele simplesmente exibe uma caixa de mensagem com o resultado da consulta.
Pondo a classe para Trabalhar
Vamos criar um projeto no VB para usar o módulo de classe criado. Inicie o VB e crie um projeto como o da figura a seguir:
Este projeto usa os seguintes
controles: - combo1 - cbofornecedor - combo2 - cbocategoria - commandbutton - Command1 |
A idéia é preencher as caixas de combinação , uma com o nome dos fornecedores e outra com as categorias existentes. O usuário irá selecionar o fornecedor e a categoria e clicar no botão Executa Consulta que irá chamar o método do nosso módulo de classe retornando o resultado desejado.
Para preencher as caixas de combinação usaremos a função - clssql.bas - definida em um módulo padrão. O código deste módulo é o seguinte:
Public db As Database Public area As Workspace Public Sub enchecombo(combo As Control,data As String,campo As String,Optional indice As Variant) '-- cria variável recordset temporária Dim arqtemp As Recordset '-----limpa combo combo.Clear '-----abre tabela como Snapshot (economiza memoria) Set arqtemp = db.OpenRecordset(data, dbOpenSnapshot) '--inicia loop através da tabela--- If arqtemp.RecordCount > 0 Then Do Until arqtemp.EOF combo.AddItem arqtemp(campo) If Not IsMissing(indice) Then combo.ItemData(combo.NewIndex) = arqtemp(indice) End If arqtemp.MoveNext Loop Else MsgBox "Não há dados ..." Exit Sub End If '---fecha recordset e seleciona primeiro opcao na combo arqtemp.Close combo.ListIndex = 0 '-----limpa memoria Set arqtemp = Nothing End Sub |
O evento Load do formulário - frmclsql - tem o seguinte código:
Private Sub Form_Load() Set area = DBEngine.Workspaces(0) dbname = "c:\teste\nwind2000.mdb" Set db = area.OpenDatabase(dbname) Call enchecombo(cbofornecedor, "fornecedores", "NomedaEmpresa", "códigodofornecedor") Call enchecombo(cbocategoria, "categorias", "NomedaCategoria", "códigodacategoria") End Sub |
Nele abrimos o banco de dados e chamamos a função enchecombo definida no módulo - clssql.bas . A função recebe os parâmetros para preencher cada combobox com os valores referentes a tabela dos fornecedores e a tabela das categorias. Basta o usuário selecionar o fornecedor e a categoria e clicar no botão de comando Executa Consulta.
Aqui temos a combobox com os dados dos fornecedores:
. |
O resultado da consulta é exibido em uma caixa de mensagem .( ver figura abaixo):
O código do botão Executa consulta é o seguinte:
Private Sub Command1_Click() Dim objSQL As Cls_sql 'define a variavel objeto Set objSQL = New Cls_sql 'define as novas propriedades do objeto With objSQL .NomedaEmpresa = cbofornecedor.Text .NomedaCategoria = cbocategoria.Text End With 'Retorna as propriedades Debug.Print objSQL.NomedaEmpresa Debug.Print objSQL.NomedaCategoria 'invoca o metodo do objeto objSQL.Executa_SQL 'destroi o objeto Set objSQL = Nothing End Sub |
-Iniciamos dimensionando uma váriavel objeto baseada na nossa classe Cls_sql , ou seja , instânciamos um objeto da classe Cls_sql .
Dim objSQL As Cls_sql
-A seguir determinamos os valores para as propriedades do objeto - objSQL
With objSQL .NomedaEmpresa = cbofornecedor.Text .NomedaCategoria = cbocategoria.Text End With
-Finalmente invocamos o método do objeto baseado na classe
objSQL.Executa_SQL
E acabou ! . Percebeu qual a vantagem dos módulos de classe ? Não ???
É obvio que a forma de exibir os resultados poderá ser melhorada , usando um msflexgrid por exemplo.
Este projeto completo está no Super CD VB.