Translate this page now :



»Programação
»Programação.NET
»Banco de Dados
»Webdesign
»Office
» Certificações Microsoft 4
»Treinamentos4
»Programação 4
»Webdesign«
»Office & User Tips«
»Grupos de Usuários
»Células Acadêmicas«
intcontpiada : 118
Banheiro moderno
Você já está cadastrado e participa do grupo de usuários de sua cidade ? Se não, comente o porque.
 
 
Faça um pequeno teste com 10 questões de VB
.:.
Teste seus conhecimentos em Visual Basic, SQL Server e ASP 3.0 com nossas provas on-line
.:.
Aprimore seus conhecimentos em programação com nosso treinamento on-line de lógica de programação
.:.
Veja nosso calendário de treinamentos
Gostou da Página?
Então

para um amigo!

Pesquisa personalizada
Pesquisar Dicas:

 






Imprimir

Baixe os fontes

Obtendo Schemas de base de dados utilizando o ADO.NET

Existem muitas aplicações que precisam obter informações sobre a estrutura de objetos na base de dados, isso é algo bem frequente. Aplicações para geração de código, por exemplo, precisam de amplas informações sobre a estrutura das bases de dados.

O data provider para OLEDB implementa recursos para obtermos a estrutura de bases de dados. Como trata-se de um data provider ligado a inúmeros bancos de dados (através dos providers OLEDB), podemos obter a estrutura de inúmeros tipos de banco de dados diferentes.

Toda essa possibilidade encontra-se no método chamado GetOleDbSchemaTable. Este método recebe 2 parâmetros : Um GUID que identifica o tipo de objeto que desejamos (tabelas, procedures, views, etc..) e um 2o parâmetro que atua como filtro para os dados que serão retornados. Este método devolve uma dataTable, tornando simples a manipulação dos dados no client.

Vamos então montar um pequeno projeto que nos permita acessar e trabalhar com os dados sobre a estrutura do banco, demonstrando desta forma como manipular estes dados, entre outros exemplos úteis.

Vamos inicialmente criar uma Windows Application com um form e colocar dois objetos no form : Uma listBox (lstObjetos) e uma DataGrid (dg).

Vamos preencher a listbox com uma lista dos tipos de objetos que poderemos estar requisitando da base de dados. Mas este preenchimento não será tão simples : Os tipos de objetos não estão em um enum, estão disponíveis na forma de propriedades da classe System.Data.OleDb.OleDbSchemaGuid, cada uma devolvendo o GUID do tipo de objeto correspondente. Precisaremos então utilizar Reflections para podermos preencher a listbox, veja :

   58         Dim p As New ArrayList

   59         Dim t As Type

   60         t = GetType(System.Data.OleDb.OleDbSchemaGuid)

   61         p.AddRange(t.GetFields)

   62         lstObjetos.DataSource = p

   63         lstObjetos.DisplayMember = "Name"

Desta forma vinculamos a listbox a um arrayList de objetos Field, que devolvem os campos existentes na classe OleDbSchemaGuid.

Sempre que houver um click na listbox vamos obter os dados referentes a este tipo de objeto e vamos exibir tais dados na dataGrid. A lista de objetos, porém, é genérica. Portanto nem todos os objetos estão disponíveis para todos os tipos de banco, precisaremos tratar isso também. Veja como fica :

   58         Dim ds As New DataSet

   59         Dim nomeTabela As String

   60         nomeTabela = DirectCast(lstObjetos.SelectedItem, FieldInfo).Name

   61 

   62 

   63         Dim dt As DataTable

   64         CN.Open()

   65         Try

   66             dt = CN.GetOleDbSchemaTable(DirectCast(lstObjetos.SelectedItem, FieldInfo).GetValue(GetType(System.Data.OleDb.OleDbSchemaGuid)), Nothing)

   67         Catch er As Exception

   68             MsgBox("Este tipo de elemento não está disponível neste provider OLEDB" & vbCrLf & er.Message)

   69             Exit Sub

   70         Finally

   71             CN.Close()

   72         End Try

   73 

   74         ds.Tables.Add(dt)

   75 

   76 

   77         dg.DataSource = ds.Tables(DirectCast(lstObjetos.SelectedItem, FieldInfo).Name)

Observe a expressão, um pouco mais complexa, utilizada como primeiro parâmetro no método GetOledbSchemaTable. Tendo o objeto FieldInfo, precisamos utilizar o método GetValue deste objeto para obter o valor de uma propriedade. Porém como as propriedades em questão são Shared, a aplicação do GetValue recebe como parâmetro um type, a própria classe OleDbSchemaGuid .

Pronto. Com essa codificação simples já temos acesso a informações de estrutura da base de dados. Agora vamos tornar esta aplicação um pouco mais sofisticada. Vamos adicionar a possibilidade do usuário fazer personalizações no que é exibido (por exemplo, cortando tipos de objetos desnecessários na listbox e colunas desnecessárias na grid) e manter a configuração feita pelo usuário entre as execuções da aplicação.

Vamos começar com a listbox. Além de possibilitar a deleção de itens da listbox precisaremos guardar os itens que foram deletados em um arraylist, o arrayList dos deletados. Poderemos serializar este arraylist para um arquivo em disco e recupera-lo posteriormente, quando a aplicação for novamente aberta. Então vamos ver como isso fica :

   86     Private Sub lstObjetos_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles lstObjetos.KeyDown

   87         If e.KeyData = Keys.Delete Then

   88             Dim c As CurrencyManager

   89             ar.Add(DirectCast(lstObjetos.SelectedItem, FieldInfo).Name)

   90             remover(DirectCast(lstObjetos.SelectedItem, FieldInfo).Name)

   91 

   92             c = Me.BindingContext(p)

   93             c.SuspendBinding()

   94             c.ResumeBinding()

   95 

   96         End If

   97     End Sub

Observe que temos então 2 arrayLists : Um arraylist com os elementos exibidos e um arraylist para guardar os elementos deletados. No exemplo acima adicionamos o nome do item deletado no arrayList de deletados (AR) e eliminamos o item deletado do array de itens exibidos. Para isso criei uma sub a parte chamada remover.

Quanto ao uso do CurrencyManager, acima, isso se deve ao fato de que uma listbox, quando vinculada a um arraylist, não se atualiza automaticamente quando o arrayList se atualiza. Esse assunto foi tema de uma dica no site BufaloInfo, veja em http://www.bufaloinfo.com.br/dicas.asp?cod=725

Veja como fica a sub Remover :

   99     Private Sub remover(ByVal nome As String)

  100         For Each f As FieldInfo In p

  101             If f.Name = nome Then

  102                 p.Remove(f)

  103                 Exit Sub

  104             End If

  105         Next

  106     End Sub

Como o arrayList ligado a combo possui objetos FieldInfo foi necessário localizar o objeto FieldInfo correto para poder elimina-lo.

Agora vejamos como fica o processo de serialização e deserialização do arrayList. Este código é especialmente interessante pois esta tarefa pode ser realizada com qualquer objeto que tenha capacidade de serialização - e são muitos.

Veja o código de serialização :

   58         If File.Exists(NomeHash) Then

   59             File.Delete(NomeHash)

   60         End If

   61         Dim obj As New BinaryFormatter

   62         Dim st As New FileStream(NomeHash, FileMode.Create)

   63         obj.Serialize(st, ar)

   64         st.Close()

Como trata-se da gravação de um arquivo em disco, tomei o cuidado de verificar se o arquivo existe e, caso exista, deleta-lo.

Com a classe BinaryFormatter (que fica em System.Runtime.Serialization.Formatters.Binary ) fica fácil fazer o processo de serialização e deserialização de um objeto, como pode observar acima. O FileStream, localizado em System.IO, completa o trabalho fazendo a gravação do resultado da serialização em um arquivo em disco.

Veja como fica a deserialização, tão simples quanto :

   59         If File.Exists(NomeHash) Then

   60             Dim obj As New BinaryFormatter

   61             Dim st As New FileStream(NomeHash, FileMode.Open)

   62             ar = obj.Deserialize(st)

   63             st.Close()

   64             For Each f As String In ar

   65                 remover(f)

   66             Next

   67         End If

Observe que após a deserialização já implementei o que desejamos : faço uma varredura no arraylist e a eliminação dos elementos deletados do arraylist principal.

Neste trecho de código utilizei um truque interessante : Em todos os pontos nos quais me refiro ao nome do arquivo utilizei uma chamada a uma propriedade, NomeHash.

O nome do arquivo propriamente é uma montagem que depende do local onde a aplicação estiver. Utilizando uma propriedade, NomeHash, centralizo em um único ponto do código a geração do nome do arquivo. Assim sendo se em algum momento for necessário alterar o código de geração do nome deste arquivo bastará altera-lo em um único local. Veja como fica a propriedade :

   98     Private ReadOnly Property NomeHash() As String

   99         Get

  100             Return (Application.StartupPath & "\hash.bin")

  101         End Get

  102     End Property

Vamos agora permitir que o usuário personalize as colunas na DataTable e mantenha essa personalização através das execuções da aplicação.

Para permitir a deleção de colunas na grid vamos criar um contextMenu. Porém para que possamos saber em que coluna o mouse estava no momento em que o contextMenu for ativado não irei vincula-lo diretamente na propriedade contextMenu da grid, mas sim ativa-lo através do evento mouseUp. Veja como fica :

  104     Private Sub dg_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles dg.MouseUp

  105         If e.Button = MouseButtons.Right Then

  106             pt = New Point(e.X, e.Y)

  107             ContextMenu1.Show(dg, pt)

  108         End If

  109     End Sub

Observe que guardei na variável pt um objeto point com as coordenadas do click. Desta forma poderemos utilizar este objeto para descobrir qual foi a coluna clicada. Veja como fica o click do menu :

  111     Private Sub MenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem1.Click

  112 

  113         Dim hit As DataGrid.HitTestInfo

  114         hit = dg.HitTest(pt)

  115         DirectCast(dg.DataSource, DataTable).Columns.RemoveAt(hit.Column)

  116 

  117     End Sub

Através do método HitTest podemos obter informações sobre um determinado ponto com relação a datagrid, descobrindo, por exemplo, qual foi a coluna clicada, para remove-la em seguida como é feito no código acima.

Partimos então para o próximo problema : Como manter a escolha das colunas através das execuções da aplicação ?

A melhor forma de fazer isso é guardando o schema do DataSet em um arquivo em disco. Precisaremos então fazer pequenas adaptações na forma de carregar o dataSet : No nosso exemplo anterior, simplesmente adicionavamos a dataTable. Agora precisaremos manter um dataSet único e chegar se a dataTable já existe ou não. Se não existe, simplesmente adicionamos, mas se já existe então precisamos preencher os dados dentro da estrutura da dataTable já existente, fazendo um Merge.

Veja como fica :

  119     Private Sub LerSchema(ByVal nome As System.Guid)

  120         Dim dt As DataTable

  121         CN.Open()

  122         Try

  123             dt = CN.GetOleDbSchemaTable(nome, Nothing)

  124         Catch er As Exception

  125             MsgBox("Este tipo de elemento não está disponível neste provider OLEDB" & vbCrLf & er.Message)

  126             Exit Sub

  127         Finally

  128             CN.Close()

  129         End Try

  130         If Not ds.Tables.Contains(dt.TableName) Then

  131             ds.Tables.Add(dt)

  132         Else

  133             ds.Merge(dt, False, MissingSchemaAction.Ignore)

  134         End If

  135     End Sub

Observe no código acima que o Merge faz uso do MissingSchemaAction. Isso porque o usuário pode ter eliminado alguns campos da tabela. Se o Merge não definisse essa opção os campos seriam re-adicionados.

Outra questão interessante é que neste ponto já transformei essa rotina em uma sub LerSchema. Essa sub é chamada do SelectedIndexChanged da listbox. Veja como fica :

  137     Private Sub lstObjetos_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstObjetos.SelectedIndexChanged

  138 

  139         Dim nomeTabela As String

  140         nomeTabela = DirectCast(lstObjetos.SelectedItem, FieldInfo).Name

  141         If Not ds.Tables.Contains(nomeTabela) Then

  142 

  143             LerSchema(DirectCast(lstObjetos.SelectedItem, FieldInfo).GetValue(GetType(System.Data.OleDb.OleDbSchemaGuid)))

  144         ElseIf ds.Tables(nomeTabela).Rows.Count = 0 Then

  145             LerSchema(DirectCast(lstObjetos.SelectedItem, FieldInfo).GetValue(GetType(System.Data.OleDb.OleDbSchemaGuid)))

  146         End If

  147 

  148         dg.DataSource = ds.Tables(DirectCast(lstObjetos.SelectedItem, FieldInfo).Name)

  149 

  150     End Sub

Se a tabela não existe no dataSet ou se está sem linhas é chamada a sub LerSchemas, do contrário é porque os dados já haviam sido carregados antes, então a tabela é apenas exibida novamente.

Serializar e deserializar o schema deste dataSet será uma tarefa bem simples, mais que no caso anterior : O dataSet não precisa que utilizemos uma classe de serialização, como antes, ele próprio possui métodos para fazer a serialização do schema.

Serializar :

   59         ds.WriteXmlSchema(NomeSchema)

Deserializar :

   59         If IO.File.Exists(NomeSchema) Then

   60             ds.ReadXmlSchema(NomeSchema)

   61         End If

Propriedade NomeSchema :

  146     Private ReadOnly Property NomeSchema() As String

  147         Get

  148             Return (Application.StartupPath & "\schema.xml")

  149         End Get

  150     End Property

Neste ponto já conseguimos permitir que o usuário personalize a aplicação e que esta personalização seja mantida, o que já torna a aplicação bem interessante.

Mas para que a aplicação fique ainda mais útil torna-se necessário permitir que a aplicação guarde não apenas uma, mas diversas configurações nomeadas. Assim sendo o usuário pode se conectar a diferentes bancos de dados e guardar as configurações de como deseja visualizar cada um.

Vamos começar criando uma classe Configuracao para agregar os dados que cada configuracao deve ter. Uma configuração terá um nome, uma string de conexão e irá também gerar um código que será anexado aos nomes de arquivos que guardarão as características da configuração. Veja como fica :

  152     <Serializable()> Public Class config

  153         Public NomeConfig As String

  154         Public Conexao As String

  155         Private _id As String

  156 

  157         Public Sub New()

  158 

  159         End Sub

  160 

  161         Public Sub New(ByVal cf As String, ByVal con As String, ByVal id As Integer)

  162             NomeConfig = cf

  163             Conexao = con

  164         End Sub

  165 

  166         Public ReadOnly Property CodigoArquivo() As String

  167             Get

  168                 Return (NomeConfig.Substring(0, 3) & _id)

  169             End Get

  170         End Property

  171 

  172         Public Overrides Function tostring() As String

  173             Return (NomeConfig)

  174         End Function

  175 

  176     End Class

Criei um construtor recebendo parâmetros, para simplificar a configuração desta classe. Uma propriedade readonly chamada CodigoArquivo, que irá gerar uma pequena string a ser anexada o nome dos arquivos. A função ToString levou um overrides para podermos definir o que desejamos que apareça em uma combo quando esta classe for inserida em uma combo.

Vamos então preparar este formulário que temos para poder lidar com essa classe. Esse formulário irá receber uma instância desta classe como parâmetro quando for aberto (o usuário já terá escolhido a configuração - faremos isso depois) e deverá utilizar as informações contidas nesta classe.

Primeiramente, uma propriedade para controlar o recebimento desta classe :

  178     Public Property configuracao() As frmConfig.config

  179         Get

  180             Return (_Configuracao)

  181         End Get

  182         Set(ByVal Value As frmConfig.config)

  183             _Configuracao = Value

  184         End Set

  185     End Property

As propriedades que geram os nomes dos arquivos passarão a utilizar esta propriedade configuração, veja :

  187     Private ReadOnly Property NomeSchema() As String

  188         Get

  189             Return (Application.StartupPath & "\schema" & Configuracao.CodigoArquivo & ".xml")

  190         End Get

  191     End Property

  192 

  193     Private ReadOnly Property NomeHash() As String

  194         Get

  195             Return (Application.StartupPath & "\hash" & Configuracao.CodigoArquivo & ".bin")

  196         End Get

  197     End Property

Podemos também exibir no título do form o nome da configuração selecionada :

   59         Me.Text = Me.configuracao.NomeConfig

Precisaremos de um botão que permita ao usuário trocar a configuração selecionada. Neste caso o ideal será transformarmos a inicialização do form (deserializações) e a finalização (serializações) em subs que possam ser chamadas de mais de um local. Veja como fica :

  198     Sub inicializarForm()

  199         Dim t As Type

  200 

  201         salvarconfig()

  202 

  203         Dim c As CurrencyManager

  204         c = Me.BindingContext(p)

  205         c.SuspendBinding()

  206 

  207         ar.Clear()

  208         p.Clear()

  209 

  210         ds = New DataSet

  211         lstObjetos.DataSource = Nothing

  212         lstObjetos.Items.Clear()

  213 

  214         Me.Text = Me.configuracao.NomeConfig

  215 

  216         t = GetType(System.Data.OleDb.OleDbSchemaGuid)

  217         p.AddRange(t.GetFields)

  218 

  219         If File.Exists(NomeHash) Then

  220             Dim obj As New BinaryFormatter

  221             Dim st As New FileStream(NomeHash, FileMode.Open)

  222             ar = obj.Deserialize(st)

  223             st.Close()

  224             For Each f As String In ar

  225                 remover(f)

  226             Next

  227         End If

  228 

  229         If IO.File.Exists(NomeSchema) Then

  230             ds.ReadXmlSchema(NomeSchema)

  231         End If

  232 

  233 

  234         lstObjetos.DataSource = p

  235         lstObjetos.DisplayMember = "Name"

  236         c.ResumeBinding()

  237     End Sub

  238 

  239     Public Sub salvarconfig()

  240         ds.WriteXmlSchema(NomeSchema)

  241 

  242 

  243         If File.Exists(NomeHash) Then

  244             File.Delete(NomeHash)

  245         End If

  246         Dim obj As New BinaryFormatter

  247         Dim st As New FileStream(NomeHash, FileMode.Create)

  248         obj.Serialize(st, ar)

  249         st.Close()

  250     End Sub

Desta forma podemos chamar essas subs do evento Load, closing, do botão e uma chama a outra (ao trocar a configuração, salva-se a anterior).

Vamos então criar um 2o form, que permitirá ao usuário selecionar a configuração desejada ou criar uma nova configuração. A aplicação passará a ser disparada por uma sub main que interligará os dois forms, veja :

  253 Module Module1

  254     Public Sub Main()

  255         Dim frm As New frmConfig

  256         Dim f As New Form1

  257         frm.ShowDialog()

  258         If frm.DialogResult = DialogResult.OK Then

  259             f.configuracao = frm.Configuracao

  260             Application.Run(f)

  261         End If

  262     End Sub

  263 End Module

No formulário para escolha da configuração, vamos chama-lo de frmConfig, vamos inserir uma combo para listar as configurações existentes, um botão para disparar a criação de uma nova configuração e um botão para dar ok na seleção de uma configuração e seguir adiante.

Teremos mais um arquivo serializado, que conterá a lista de configurações existentes. Precisaremos no load do form fazer a deserialização deste arquivo. Veja como fica :

   59         If File.Exists(arquivoConfig) Then

   60             Dim obj As New BinaryFormatter

   61             Dim st As New FileStream(arquivoConfig, FileMode.Open)

   62             hs = obj.Deserialize(st)

   63             st.Close()

   64         End If

   65         cmbConfigs.DataSource = hs

  258     Public ReadOnly Property arquivoConfig() As String

  259         Get

  260             Return (Application.StartupPath & "/configs.bin")

  261         End Get

  262     End Property

Quando um item na combo for selecionado, habilitamos o botão ok. Quando o botão Ok for clicado, atribuimos a classe selecionada na variável Configuracao. Veja como fica :

  265     Public Configuracao As config

  266 

  267     Private Sub cmbConfigs_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbConfigs.SelectedIndexChanged

  268         cmdOk.Enabled = True

  269     End Sub

  270 

  271     Private Sub cmdOk_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdOk.Click

  272         Me.Configuracao = DirectCast(cmbConfigs.SelectedItem, config)

  273     End Sub

Quando o usuário clicar no botão para adicionar uma nova configuração precisaremos fazer os seguintes passos :

  • Perguntar o nome da nova configuração
  • Permitir que o usuário monte uma string de conexão
  • Criar uma nova instância da classe config, adicionar no arrayList e fazer refresh da combo


Veja como fica :

   59         Dim nomeConfig As String

   60         nomeConfig = InputBox("Informe o nome da nova configuração", "Nova Configuração")

   61 

   62         If nomeConfig = "" Then

   63             Exit Sub

   64         End If

   65 

   66         Dim dataLink As Object = Microsoft.VisualBasic.Interaction.CreateObject("DataLinks")

   67         dataLink.hWnd = Me.Handle

   68 

   69         Dim o As Object = dataLink.PromptNew()

   70         If o Is Nothing Then

   71             Exit Sub

   72         Else

   73             Dim cl As New config(nomeConfig, o.connectionstring.ToString, hs.Count)

   74             hs.Add(cl)

   75             Dim c As CurrencyManager

   76             c = Me.BindingContext(hs)

   77             c.SuspendBinding()

   78             c.ResumeBinding()

   79 

   80         End If

Observe que neste código utilizei um truque para exibir para o usuário a própria janela de configuração de uma conexão do OLEDB, permitindo desta forma que o usuário crie a string de conexão em um ambiente já familiar a ele. Isso foi exposto em uma dica em http://www.bufaloinfo.com.br/dicas.asp?cod=430

Agora que chegamos neste ponto e a aplicação já está funcionando e guardando configurações diversas do usuário, vamos então inserir na aplicação a capacidade de fazer filtragens das informações exibidas. Vamos criar 2 tipos de filtragem : Uma filtragem simples, aplicada sobre os dados exibidos e uma filtragem relacionada, por exemplo, o usuário desejará ver os campos de uma determinada tabela.

Vamos começar, claro, pela filtragem mais simples. Precisaremos criar um formulário novo através do qual o usuário possa definir a filtragem a ser realizada. Vamos chamar este novo formulário de frmRestricoes.

Muitos objetos deste formulário deverão ser dinâmicos. Ele deverá exibir os campos existentes na DataTable que será filtrada (exibir mesmo campos que tenham sido excluidos pelo usuário) e permitir que o usuário digite, para cada campo, o critério de filtro, ou deixe o campo vazio. Assim sendo deverão ser criados labels e textboxes tantos quantos forem os campos da dataTable sendo filtrada.

Mas isso se complica um pouco mais. As DataTables possuem os campos devolvidos pelo provider OLEDB, fornecendo informações sobre determinados tipos de objetos no banco. O problema é que alguns dos campos em cada DataTable são específicos de determinados data providers e, por isso, não podem ser usados como parte das restrições. As DataTables tem um conjunto de campos genéricos, estes podendo ser usados nas restrições, e um conjunto de campos específicos, que não podem. O número de campos que podem ou não serem utilizados nas restrições variam para cada DataTable.

No endereço http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbschema_rowsets.asp encontrei documentação sobre quantas colunas de cada tipo de DataTable podem ser usadas como critério. Isso acaba sendo algo fixo, veja como codifiquei, para resolver o problema :

  292     Private Sub DefinirRestricoes()

  293         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Assertions, 3)

  294         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Catalogs, 1)

  295         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Character_Sets, 3)

  296         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Check_Constraints, 3)

  297         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Check_Constraints_By_Table, 6)

  298         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Collations, 3)

  299         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Column_Domain_Usage, 3)

  300         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Column_Privileges, 6)

  301         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Columns, 4)

  302         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Constraint_Column_Usage, 7)

  303         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Constraint_Table_Usage, 5)

  304         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Foreign_Keys, 6)

  305         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Indexes, 5)

  306         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Key_Column_Usage, 7)

  307         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Primary_Keys, 3)

  308         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Procedure_Columns, 4)

  309         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Procedure_Parameters, 4)

  310         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Procedures, 4)

  311         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Provider_Types, 2)

  312         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Referential_Constraints, 3)

  313         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Schemata, 3)

  314         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Statistics, 3)

  315         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Table_Constraints, 7)

  316         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Table_Privileges, 5)

  317         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Table_Statistics, 7)

  318         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Tables, 4)

  319         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Tables_Info, 4)

  320         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Translations, 3)

  321         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Usage_Privileges, 6)

  322         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.View_Column_Usage, 3)

  323         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.View_Table_Usage, 3)

  324         hsNumRestricoes.Add(System.Data.OleDb.OleDbSchemaGuid.Views, 3)

  325     End Sub