Exportar (0) Imprimir
Expandir Tudo

Lendo a estrutura de bancos de dados com ADO.NET

por Gabriel Brenner*

Para ler todas as matérias da FórumAccess, assine a revista no endereço http://www.forumaccess.com.br/novo/

Este artigo discute

Este artigo usa as seguintes tecnologias:

  • Estrutura de Banco de dados com ADO .NET

VB.NET 2003

 

 

Ler a estrutura de um banco de dados pode suprir uma série de necessidades e possibilitar automações que venham a agilizar e facilitar o desenvolvimento de sistemas. O artigo abordará a utilização do ADO.NET para ler a estrutura de uma tabela e a criação de uma classe que possibilite encapsular o código de leitura e facilitar o consumo das informações. Entre as automações que podem ser criadas a partir de uma aplicação que aproveite a estrutura das tabelas de um banco de dados, pode-se citar um escritor de classes, que monta o esqueleto das classes de um projeto conforme padrão de implementação adotado ou ainda a automação completa das operações de um formulário, conforme mostrado no artigo Parametrizando uma janela de cadastro nesta mesma edição. No entanto, este artigo irá restringir-se a demonstrar como o Leitor poderá ler a estrutura de uma tabela e, como criar uma classe que encapsule toda a lógica de leitura, utilizando polimorfismo para que em uma mesma classe seja possível ler, através de métodos com o mesmo nome, a estrutura de tabelas de um banco de dados Access e de um banco de dados do SQL-Server.

LENDO A ESTRUTURA DE UMA TABELA COM ADO.NET

Para ler a estrutura de uma tabela, o leitor fará uso de três objetos do ADO.NET: o DataReader, Command e o DataTable. O objeto Command recebe uma expressão SQL para apontar o DataReader para acessar a estrutura da tabela desejada. O método Execute-Reader recebe como parâmetro o que deseja ser acessado e, para ler a estrutura da tabela, o parâmetro deve ser CommandBehavior. KeyInfo. O DataReader é utilizado para atribuir o esquema da tabela a um DataTable, que poderá ser utilizado pelo desenvolvedor. A Figura 1 ilustra a estrutura da tabelaTipoCampos que foicarregada em um DataTable, atribuída a um DataGrid, e a Lista 1ilustra o código utilizado para carregar os dados no DataGrid.

Cc580593.R65_LendoEstruturasADONET_img_0(pt-br,MSDN.10).jpg
Figura 1 – Estrutura da tabela TipoCampos

A tabelaTipoCampos é uma das tabelas do banco Cadastro.mdb que acompanha o exemplo (TableStruct.zip), disponível para download no site da revista (http://www.forumaccess.com.br).

Lista 1 – Carregando a estrutura da tabela TipoCampos no GrdItens

Private Sub CmdCarregar_Click(...

Dim Dr As OleDb.OleDbDataReader

Dim Cm As New OleDb.OleDbCommand("Select Top 1 * from TipoCampos", Cn)

Dr = Cm.ExecuteReader(CommandBehavior.KeyInfo)

Dim Dt As DataTable = Dr.GetSchemaTable

Dr.Close()

Dr = Nothing

Cm.Dispose()

GrdItens.DataSource = Dt

End Sub

As principais colunas da estrutura da tabeDataTable estão descritas na Tabela 1.

Cc580593.R65_LendoEstruturasADONET_img_2(pt-br,MSDN.10).jpg
Tabela 1 – Descrição das colunas retornadas pelo ADO.NET ao ler a estrutura de uma tabela

CRIANDO UMA CLASSE PARA ENCAPSULAR A LEITURA DA ESTRUTURA

O ADO.NET possui classes distintas para acessar diferentes basesde dados. Exemplos disso são as classes dos NameSpaces OLEDB e as do SQLClient. Apesar de possuírem a mesma estrutura, se o desenvolvedor resolver migrar um projeto do Access para o SQL- Server, ele terá que modificar todo o projeto. O objetivo da classe a ser criada será o de fornecer uma forma única para ler a estrutura de uma tabela, independente do banco de dados que esteja sendo utilizado. A classe está implementada para ler a estrutura de uma tabela do SQL-Server ou do Access, utilizando polimorfismo para disponibilizar métodos com nomes iguais recebendo parâmetros diferentes, tornando transparente seu uso para o desenvolvedor. O leitor pode utilizar a mesma idéia para acrescentar as outras bibliotecas de acesso a dados, como a ODBC e a do ORACLE. O projeto GetTableStructure é um Class Library e dará origem a uma DLL que poderá ser utilizada em qualquer projeto .NET. Na classe ClsTabela estarão contidos todos os métodos que retornaram a estrutura da Tabela. Para retornar a estrutura da tabela são utilizados dois Structure:

Structure stCampo: Representa a estrutura de um campo da tabela. é utilizado no Structure stTabela que contém um array de stCampo, representando todos os campos da tabela desejada.

Structure stTabela: Representa a tabela. Além da estrutura de campos (array de stCampo), possui o nome da tabela, o total de campos, um array isolando as chaves primárias dos demais campos e o total de campos que compõe a chave primária. Os structure StCampo e StTabela estão ilustrados na lista 2.

Lista 2 – Declaração dos structure StCampo e StTabela que são utilizados na classe ClsTabela

Public Structure stCampo

Dim Index As Integer

Dim Chave As Boolean

Dim Nome As String

Dim Tamanho As Integer

Dim Precisao As Integer

Dim Tipo As EnumTipo

Dim Obrigatorio As Boolean

End Structure

Public Structure stTabela

Dim Nome As String

Dim TotalCamposChaves As Integer

Dim ChavePrimaria() As stCampo

Dim TotalCampos As Integer

Dim Campos() As stCampo

End Structure 

O artigo trabalha a estrutura somente com esses dados. Caso o leitor ache necessário maiores detalhes sobre cada campo, basta acrescentar o detalhe na estrutura stCampo e atribuir o valor desejado ao detalhe no momento em que a classe carrega os dados da tabela. Os métodos da classe retornaram um objeto stTabela, que poderá ser utilizado por qualquer projeto que venha a utilizar a dll criada, não dependendo mais dos objetos do ADO.NET. A função ProcessaDetalhesTabela, presente dentro da classe ClsTabela, recebe um DataTable contendo a estrutura da tabela e carrega os Structure, retornando para o método que a chamou um Structure stTabela carregado.

Localize o código da função ProcessaDetalhesTabela, na classe clsTabela. Ela atribui os dados a uma variável iTabela que é do Tipo stTabela. Primeiro atribui dados globais, como o nome da tabela e a quantidade de campos, para, após percorrer campo a campo da estrutura armazenada no DataTable, montar os dados dos campos do objeto stTabela criado. Existe uma complicação no final para atribuir as chaves ao Array ChavePrimaria, porque inicialmente não se sabe quantos campos compõem a chave e é necessário a cada chave identificada redimensionar o array antes de atribuir os dados do campo. Detalhes não são colocados nos campos que compõem a chave para simplificar o código. Caso o leitor deseje acrescentar valores a todos os detalhes dos campos que compõem a chave não há problema algum, bastando para isso editar o código.

UTILIZANDO POLIMORFISMO PARA SUPORTE A MÚLTIPLOS BANCOS

A função ProcessaDetalhesTabela recebe um DataTable contendo a estrutura da tabela conforme demonstrado na Lista 1. O problema agora é como uma mesma classe pode trabalhar com diferentes tipos de banco de dados se os objetos utilizados para acesso são diferentes? Esse problema pode ser resolvido utilizando um recurso da orientação a objetos, chamado polimorfismo. Ele possibilita que uma mesma classe possua métodos com o mesmo nome, até mesmo com a mesma quantidade de parâmetros, desde que os parâmetros sejam diferentes (seja em tipo, quantidade ou nome). Tendo em mãos essa informação, bastou trabalhar métodos com nomes iguais, mas que recebessem como parâmetros ou os dados necessários para trabalhar com o banco desejado ou os objetos do banco desejado, modificando sua implementação de acordo com o NameSpace utilizado, tornando com isso o uso dos métodos transparentes para o desenvolvedor final. Os métodos implementados estão ilustrados na Lista 3.

‘Métodos responsáveis por ler a estrutura de uma tabela de um banco de dados

Access

‘O primeiro método, parte do pressuposto que não existe uma conexão aberta

com o banco em questão e recebe os parâmetros necessários para abrí-la

e após estar aberta, chama o segundo método que recebe a conexão como

parâmetro e lê a estrutura da tabela, retornando como resultado o resultado da

execução da função ProcessaDetalhesTabela

Public Function Tabela(ByVal AccessDatabase As String, ByVal PWD As String, ByVal pTabela As String) As stTabela

Dim Cn As OleDb.OleDbConnection

If PWD.Trim <> "" Then

Cn = New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & 
AccessDatabase & ";Jet OLEDB:Database Password=" & PWD & ";")

Else

Cn = New OleDb.OleDbConnection("Provider=Microsof.Jet.OLEDB.4.0; Data Source=" & AccessDatabase & 
";User Id=admin;Password=;")

End If

Return Tabela(Cn, pTabela)

Cn.Close()

Cn.Dispose()

End Function

Public Function Tabela(ByRef Cn As OleDb.OleDbConnection, ByVal pTabela As String) As stTabela

Dim Dr As OleDb.OleDbDataReader

Dim Cm As New OleDb.OleDbCommand("Select Top 1 * from " & pTabela, Cn)

If Cm.Connection.State = 0 Then Cm.Connection.Open()

Dr = Cm.ExecuteReader(CommandBehavior.KeyInfo)

Dim Dt As DataTable = Dr.GetSchemaTable

Dr.Close()

Dr = Nothing

Cm.Dispose()

Return ProcessaDetalhesTabela(Dt)

End Function

‘Métodos responsáveis por ler a estrutura de uma tabela em um banco do

SQL-Server

‘Funciona no mesmo esquema dos dois métodos anteriores. Um parte do

princípio que não existe uma conexão aberta e o outro recebe uma conexão

como parâmetro. Ambos retornam o mesmo resultado

Public Function Tabela(ByVal Server As String, ByVal Database As String, ByVal UID As String, ByVal PWD 
As String, ByVal pTabela As String) As stTabela

Dim Cn As New SqlClient.SqlConnection("Server=" & Server & ";Database=" & Database & ";UID=" 
& UID & ";Pwd=" & PWD)

Return Tabela(Cn, pTabela)

Cn.Close()

Cn.Dispose()

End Function

Public Function Tabela(ByRef Cn As SqlClient.SqlConnection, ByVal pTabela As String) As stTabela

Dim Dr As SqlClient.SqlDataReader

Dim Cm As New SqlClient.SqlCommand("Select Top 1 * from " & pTabela, Cn)

If Cm.Connection.State = 0 Then Cm.Connection.Open()

Dr = Cm.ExecuteReader(CommandBehavior.KeyInfo)

Dim Dt As DataTable = Dr.GetSchemaTable

Dr.Close()

Dr = Nothing

Cm.Dispose()

Return ProcessaDetalhesTabela(Dt)

End Function 

O exemplo contém quatro funções Tabela. As duas primeiras fornecem acesso a tabelas de banco de dados Access e, as duas restantes, acesso a tabelas do banco SQL-Server. O leitor pode implementar acesso a novos bancos, simplesmente acrescentando mais métodos com o mesmo nome, com assinaturas diferentes (parâmetros diferentes ou de tipos diferentes).

CONSUMINDO A CLASSE DE LEITURA

O projeto de exemplo disponibilizado para download possui uma solução com dois projetos, um com a criação da dll de leitura e outro que exemplifica o consumo direto a partir de um DataTable e como utilizar a classe diretamente em um programa. A Lista 4 ilustra o código utilizado para acessar tanto a estrutura de uma tabela no Access quanto para acessar a estrutura de uma tabela no SQL-Server.

Lista 4 – Lendo estruturas de tabelas através da classe criada

Private Sub MnuLerClasse_Click(...

Dim ClTabela As New GetTableStruct.ClsTabela

Dim Tabela As GetTableStruct.ClsTabela.stTabela

Tabela = ClTabela.Tabela(Cn, "TipoCampos")

ClTabela = Nothing

MsgBox(Tabela.TotalCampos)

MsgBox(Tabela.Campos(0).Nome)

End Sub

Private Sub MnuSQLServer_Click(...

Dim CnS As New SqlClient.SqlConnection

CnS.ConnectionString = "Server=localhost;Database=Northwind;UID=Sa ;PWD="

CnS.Open()

Dim ClTabela As New GetTableStruct.ClsTabela

Dim Tabela As GetTableStruct.ClsTabela.stTabela

Tabela = ClTabela.Tabela(CnS, "Products")

ClTabela = Nothing

MsgBox(Tabela.TotalCampos)

MsgBox(Tabela.Campos(0).Nome)

CnS.Close()

End Sub

Observe que o código não se modifica em nada, somente mudando a conexão utilizada, ao invés de uma que esteja apontando para o Access e seja do tipo OLEDB, utilizar uma que esteja apontando para o SQL-Server e seja SQL-Client. A conexão com o Access está sendo aberta na rotina Sub Main do programa e a rotina com o SQL-Server, diretamente no procedimento que lê a estrutura.

CONCLUSÃO

O artigo ensina ao leitor como ler a estrutura de tabelas de banco de dados, utilizando ADO.NET, e trabalha a criação de uma classe que leia essa estrutura e forneça os dados devidamente separados para que o desenvolvedor os use em seus futuros sistemas. Entre a vantagem de isolar a leitura da estrutura em uma dll, a mais importante é que a mesma implementação passa a servir para tipos de banco de dados diferentes, sem a preocupação com as bibliotecas de acesso diferente. Com base no artigo, o leitor aprendeu mais sobre polimorfismo, para que ele serve e como utilizar esse recurso, aprendendo também como criar e utilizar structures em suas aplicações. Com o conhecimento adquirido, oleitor poderá se desenvolver tanto na utilização de polimorfismo, quanto na utilização de structures, evoluindo cada vez mais o seu conhecimento na tecnologia. É importante para o leitor ler o artigo Parametrizando uma janela de cadastro, também publicado nesta edição, que cria umajanela de cadastro parametrizada, utilizando a classe deleitura de estrutura de tabelas trabalhada nesse artigo e com uma utilidade prática para ela. Um grande abraço e até o próximo artigo.

* Gabriel Brenner é Bacharel em Sistemas de Informação, desenvolvedor de sistemas Windows e WEB pelas Indústrias Nucleares do Brasil S/A (http://www.inb.gov.br), professor titular do curso de graduação em Sistemas de Informação da Faculdade de Ciências Econômicas, Administrativas e da Computação Dom Bosco (http://www.aedb.br). Atualmente cursa pós-graduação em Análise, Projeto e Gerência de Sistemas na Escola de Ciências Exatas e Tecnologia no Centro Universitário da Cidade.

Mostrar:
© 2014 Microsoft