Usando Datasets Tipados

Propaganda
Usando Datasets Tipados
Por Mauro Sant’Anna ([email protected]). Mauro é um “MSDN Regional
Director”, consultor e instrutor da MAS Informática (www.mas.com.br), tendo
ministrado treinamentos na arquitetura .NET desde outubro de 2000.
Uma das características da arquitetura de bancos de dados ADO.NET é a facilidade para
trabalhar em modo desconectado. Este modo é o que se adapta melhor ao uso em
conjunto com servidores de aplicativos, onde a manutenção de estado através de cursores
ou conexões abertas é um sério empecilho a performance e “escalabilidade”.
O “Typed DataSet” é o tipo perfeito para ser usado como “moeda de troca” entre as
diversas “camadas” do seu aplicativo. Saber como criá-los e manipulá-los é essencial
para utilizá-los bem.
Não pretendo neste artigo entrar em méritos de metodologia e projetos em múltiplas
camadas, mas os leitores que tiverem experiência com estas disciplinas com certeza
conseguirão reconhecer nos Typed Datasets grandes aliados.
Este artigo supõe uma certa familiaridade com o Visual Studio .NET e também que você
tenha um servidor de banco de dados SQL Server instalado para testes.
Criando um projeto de testes
Crie um novo projeto do tipo “Windows Application” em Visual Basic. Adicione ao
formulário um componente OleDbDataAdapter. A seguinte caixa de diálogo aparecerá:
Pressione “Next”:
Vamos agora criar uma conexão à base “Northwind”, um banco de dados de exemplo que
acompanha o SQL Server. Clique em “New Connection” e entre os dados abaixo
(evidentemente o nome do servidor será diferente, correspondendo a algum servidor na
sua rede):
Clique “Ok”; você voltará à tela anterior, mas com a base “Northwind” selecionada:
Clique “Next”:
Clique “Next” novamente e entre a query “select * from Products”:
Clique em “Finish”. Observe que foram criados vários componentes:

OleDbConnection1: Visível no formulário; encapsula a conexão ao banco de
dados;

OleDbDataAdapter1: Visível no formulário; fará a comunicação entre o DataSet
e a base de dados;

OleDbSelectCommand1: Não visível no formulário; encapsula um comando SQL
SELECT.

OleDbInsertCommand1, OleDbUpdateCommand1, OleDbDeleteCommand1: Não
visíveis no formulário; encapsulam comandos SQL de atualização logicamente
associados ao comando SQLECT.
É possível modificar os comandos SQL criados, caso eles não sejam adequados. Por
exemplo, você pode desejar omitir a atualização em um campo calculado ou de
“autoincremento”.
Criando Datasets tipados
Os DataSets tipados podem ser criados de diversas maneiras:
1. Adicionando um DataSet ao projeto em “Project | Add New Item | Dataset”;
2. A partir de um componente DataAdapter, tendo como base o conjunto de
resultado de uma consulta a banco de dados.
No nosso caso, usaremos a segunda maneira. Clique com o botão direito no componente
OleDbDataAdapter1 ou no formulário e selecione “Generate DataSet”:
Criaremos um novo DataSet com o nome “Northwind_Products”:
Entre o nome e clique “Ok”. O projeto terá agora uma classe DataSet no “Solution
Explorer” e uma instância desta classe no formulário:
Observe que NorthWind_Products representa uma classe. Você pode pedir “Show All
Files” no “Solution Explorer” e abrir o arquivo “Northwind_Products.vb” que contém o
código fonte desta classe. Este fonte foi criado automaticamente e não faz sentido
modificá-lo. Esta classe pode ser usada em diversas situações:

Como tipo de parâmetro de uma função que implementa alguma regra de negócio
ou atualiza a base de dados;

Como tipo de retorno de uma função que efetua uma consulta ao banco de dados;

Como base para criação de instâncias não só do próprio DataSet, como também
das tabelas e linhas das tabelas que ele contém para manipulações em lote.
Já “Northwind_Products1” representa uma instância de NorthWind_Products. Esta
instância pode ser usada em diversas situações, por exemplo:

Como argumento do método Fill de um componente DataAdapter para efetuar
uma consulta e preenchê-lo com o conjunto de resultado;

Como argumento do método Update de um componente DataAdapter para
atualizar a base de dados usando os comandos de atualização associados ao
DataAdapter;

Para atualizações com código “batch” de programação;

Como argumento de funções.
Preenchendo e atualizando
Veremos como usar o DataSet em um aplicativo. Acrescente componentes de forma a ter
o formulário parecido com o seguinte:
Note que o componente na parte inferior é um DataGrid. Ajustamos duas de suas
propriedades, de forma a se referir à tabela Products do nosso DataSet:

DataSource: Northwind_Products1;

DataMember: Products.
O preenchimento do DataSet é feito a partir do botão “Consulta” com o método Fill do
DataAdapter:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
' Preenche o DataSet com o resultado da consulta
OleDbDataAdapter1.Fill(Northwind_Products1)
End Sub
Note um detalhe importante: embora estejamos preenchendo o DataSet com o conteúdo
completo de uma tabela, este procedimento só deve ser feito com tabelas pequenas. O
mais comum é usar uma query parametrizada com uma cláusula WHERE, de forma a
limitar o tamanho do conjunto de resultado.
Depois de preencher o DataSet, o usuário poderá atualizá-lo através de código ou
diretamente no DataGrid. Para enviar as atualizações de volta ao banco de dados (como
no botão “Atualiza”), o código é o seguinte:
' Submete atualizações
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button2.Click
' Verifica se existem mudanças
If Northwind_Products1.HasChanges() Then
' Pega as modificações
Dim Modificados As DataSet = Northwind_Products1.GetChanges()
' Existem mesmo?
If Not Modificados Is Nothing Then
' Submete modificações ao banco
OleDbDataAdapter1.Update(Modificados)
' Limpa buffer de dados modificados
Northwind_Products1.AcceptChanges()
End If
End If
End Sub
Observe que extraímos as mudanças para outro DataSet que por sua vez é passado como
argumento do método Update do DataAdapter. O método Update envia ao banco de
dados as atualizações efetuadas em uma instância em memória do DataSet.
Atualizações Batch
É possível atualizar a instância do DataSet em memória tanto através de controles
vinculados, como no caso do DataGrid, como também através de código. Veja alguns
exemplos.
Atualiza um campo de todas as linhas
As tabelas dentro do DataSet não possuem “cursores” ou “registro corrente”. Elas são
acessadas como se fossem arrays. Veja duas versões para código que aumenta preço de
todos os produtos.
' Aumenta preço, versão 1
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button3.Click
' Declara uma instância da linha
Dim Linha As Northwind_Products.ProductsRow
' Varre a tabela inteira
For Each Linha In Northwind_Products1.Products
' Modifica
Linha.UnitPrice *= 1 + (NumericUpDown1.Value / 100)
Next
End Sub
' Aumenta preço, versão 2
Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button8.Click
' Declara uma instância da linha
Dim Linha As Northwind_Products.ProductsRow
' Declara variável de controle de loop
Dim I As Integer
' Varre a tabela inteira
For I = 0 To Northwind_Products1.Products.Rows.Count - 1
' Pega a linha
Linha = Northwind_Products1.Products(I)
' Modifica
Linha.UnitPrice *= 1 + (NumericUpDown1.Value / 100)
Next
End Sub
Insere um registro
Podemos inserir registros passando os valores de cada campo. Estes valores podem vir de
controles não-vinculados, programas de importação ou qualquer outra fonte. Veja um
exemplo que insere um registro com valores fixos.
Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button6.Click
' Insere uma linha com valores específicos
Northwind_Products1.Products.AddProductsRow( _
"Cerveja Touro Azul", 10, 1, "12 12oz cans", 6.45D, 100, 250, 150, False)
End Sub
Pesquisa dada chave primária
Cada tabela de um DataSet tipado contém um método que pesquisa a existência de uma
linha dada uma chave primária. Veja um exemplo que pesquisa dado o código do
produto.
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button4.Click
' Converte ID para inteiro
Dim ID As Integer = Convert.ToInt32(TextBox1.Text)
' Declara uma instância da linha
Dim Linha As Northwind_Products.ProductsRow =
Northwind_Products1.Products.FindByProductID(ID)
' Achou alguma coisa?
If Linha Is Nothing Then
MsgBox("Não Achado")
Else
MsgBox("Achado: " & Linha.ProductName)
End If
End Sub
Filtros
Podemos criar um filtro com o componente DataView, mas uma alternativa é usar o
método Select do DataTable. Este método aceita uma expressão semelhante a uma
cláusula WHERE do SQL e retorna um array de linhas que atendem ao critério.
O exemplo abaixo efetua pesquisa dado o nome do produto.
Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button7.Click
' Declara um array de linhas
Dim Linhas() As DataRow
' Cria um filtro
Linhas = Northwind_Products1.Products.Select("ProductName = '" &
TextBox1.Text.Trim() & "'")
' Verifica se a pesquisa achou alguma coisa
If Linhas.Length > 0 Then
' Declara uma linha
Dim Linha As Northwind_Products.ProductsRow
' Pega a primeira linha
Linha = CType(Linhas(0), Northwind_Products.ProductsRow)
MsgBox(Linha.ProductID & " - " & Linha.ProductName)
Else
MsgBox("Não Achado")
End If
End Sub
Apagando
Para apagar um registro basta chamar o método Remove de DataTable. Usualmente
efetuamos uma pesquisa antes para saber que linha estamos apagando. O exemplo abaixo
apaga um registro dado o código do produto.
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button5.Click
' Converte ID para inteiro
Dim ID As Integer = Convert.ToInt32(TextBox1.Text)
' Declara uma instância da linha
Dim Linha As Northwind_Products.ProductsRow =
Northwind_Products1.Products.FindByProductID(ID)
' Achou alguma coisa?
If Linha Is Nothing Then
MsgBox("Não Achado")
Else
Northwind_Products1.Products.Rows.Remove(Linha)
End If
End Sub
Conclusão
Os DataSets tipados facilitam bastante a manipulação de bancos de dados de forma
desconectada.
Download