C# - ADO .NET para iniciantes V - SqlDataAdapter e DataSet
Esta chegando agora ???
Então acompanhe os primeiros artigos:
Se você já conhece VB .NET e esta querendo a aprender C# sugiro que você leia o meu artigo:
O material necessário para acompanhar o curso é: (Irei utilizar o Visual C# 2008 Express Edition)
1-
Visual C# 2008 Express
Edition (vou dar preferência ao Visual C#)
2- SharpDevelop 2.2
(opcional)
3- SQL Server 2005 Express Edition
No artigo anterior escrevemos sobre o DataReader, e, embora o objeto DataReader seja rápido e muito simples de usar, em muitas situações, teremos que efetuar operações em nossos dados que vão além da exibição e movimentação somente para frente; muitas vezes teremos que realizar operações de inclusão, alteração, exclusão, etc., e, neste caso as classes DataSet e SqlDataAdapter são as mais indicadas para serem usadas.
A classe DataSet
O DataSet representa um conjunto de dados em memória retornados de uma fonte de dados e consiste de uma coleção de objeto DataTable que você pode inter-relacionar usando os objetos DataRelations. Você também pode forçar a integridade dos dados em um DataSet usando os objetos UniqueConstraints e ForeignKeyConstraints.
Um
DataSet é essencialmente um banco de dados em memória, contendo
múltiplas tabelas, constraints, consultas, ordenações e a habilidade de
persistir o seu estado em um arquivo XML. Você pode usar um SqlDataAdapter para preencher um DataSet com linhas de uma consulta feita em um banco de dados SQL Server. (Se acessar um banco de dados Access você usa um objeto OledbDataAdapter). Uma vez populadas você pode realizar alterações no DataSet, incluindo e excluindo linhas (rows), efetuando ordenações, etc, e então usar o objeto SqlDataAdpater novamente para refletir estas alterações no banco de dados original usando um comando SQL apropriado como UPDATE, DELETE, INSERT. |
Os dados estão contidos essencialmente no objeto DataTable mas é a coleção DataRelationCollection que permite que você a hierarquia da tabela. As tabelas estão contidas na coleção DataTableCollection que é acessada através da propriedade Tables.
Lembre-se que ao usar um DataSet você esta trabalhando com uma cópia dos dados em memória e por isso qualquer atualização feita nos dados tem que ser refletida na fonte de dados de origem, de outra forma , se você não atualizar os dados originais com as alterações a fonte de dados não será atualizada.
Os dados internos contidos em um DataSet são mantidos no formato XML e a estrutura do DataSet é definida pelo XSD (XML Schema Definition Language), ou seja, XML e DataSet estão intimamente ligados.
A principal característica do DataSet é totalmente desconectado, você pode usar um DataSet para armazenar dados de um banco de dados e pode também mover os dados de um DataSet para um banco de dados, mas o próprio DataSet não faz conexão alguma com o banco de dados, ele nem mesmo tem um objeto para realizar tal conexão .
Resumindo as funcionalidades do DataSet:
- Funciona como um cache in-memory, ou
seja, você terá as tabelas disponíveis para uso, podendo fazer acesso aleatório
aos registros, inserir, alterar e deletar registros da tabela;
- Opera desconectado do banco, assim , você trabalha com os registros sem
usar uma conexão do banco de dados;
- Opera com n tabelas por vez, e permite a possibilidade de relacionamento
entre as mesmas além de funcionalidades como ordenação, filtragem, etc.
Nota: A conexão utilizada pelo DataSet não necessita
ser aberta e/ou fechada manualmente. Ao chamar o método Fill do
DataAdapter a conexão é aberta, são coletados os dados solicitados e a conexão é
fechada. (No caso do DataReader você tem que abrir e fechar)
A classe SqlDataAdapter
A classe SqlDataAdapter serve como uma ponte entre o DataSet e o banco de dados SQL Server para retornar e salvar dados.
O SqlDataAdapter fornece esta ponte da seguinte forma:
De forma geral em uma implementação com mais de uma camada os passos para criar e atualizar um DataSet e em seguida atualizar os dados originais são:
Criando um DataSet
Todos as classes relacionadas como DataSet, DataAdapter, DataTable, DataRow etc estão disponíveis no namespace System.Data.
A primeira coisa a fazer é definir o namespace que pode ser feito da seguinte forma:
Em uma página ASP .NET | Em um arquivo C#: |
<%@ Import Namespace="System.Data" %> | using System.Data; |
Para criar um objeto DataSet você usa a seguinte sintaxe: DataSet <nomedoDataSet> = new DataSet();
DataSet dsClientes = new DataSet();
Observe que o construtor DataSet não requer nenhum parâmetro, porém existe um construtor sobrecarregado que aceita uma string para o nome do DataSet o qual é usado se você deseja serializar os dados para o formato XML.
Criando um SqlDataAdater
Um SqlDataAdapter trata os comandos SQL e o objeto Connection para leitura e escrita de dados. Para inicializar um SqlDataAdaptar informamos um comando SQL e um objeto Connection que definia conexão com a fonte de dados:
SqlDataAdapter daClientes = new SqlDataAdapter("Select codigo, Nome from Clientes", conexaoBD);
No código acima criamos um novo SqlDataAdpater , daClientes onde o comando SQL Select especifica que iremos ler os dados para o DataSet e o objeto Connection , conexaoBD, que deverá já ter sido iniciado, mas não aberto.
É responsabilidade do SqlDataAdpater abrir e fechar a conexão durante a chamada dos métodos Fill e Update.
Para usar comandos SQL para incluir, atualizar e deletar temos duas maneiras distintas:
O
objeto SqlDataAdapter não gera automaticamente comandos
Transact-SQL necessários para ajustar as alterações feitas a um DataSet
associado com uma instância do SQL Server.
Você pode , no entanto, criar um objeto SqlCommandBuilder para gerar automaticamente estes comandos para atualizações em uma tabela única . Veja abaixo um exemplo :
SqlCommandBuilder cmdBldr = new SqlCommandBuilder(daClientes); |
O comando SqlCommandBuilder é instanciado usando como parâmetro a instância do SqlDataAdatper, no caso daClientes, dessa forma o SqlCommandBuilder irá ler os comandos SQL e atribuir os novos comandos as propriedades Insert, Update e Delete do SqlDataAdapter.
o SqlCommandBuilder tem a limitação de gerar os comandos apenas para uma única tabela, se você precisar trabalhar com mais de uma tabela ou usar um Join terá que usar as propriedades da classe SqlDataAdapter.
Preenchendo um DataSet
Depois de criar instâncias de um DataSet e de um SqlDataAdpater você precisa preencher o DataSet usando o método Fill do SqlDataAdapter:
daClientes.Fill(dsClientes,
"Clientes");
O método Fill , usa dois parâmetros :
Nota: O método Fill possui uma sobrecarga que usa somente o DataSet; neste caso a tabela criada terá um nome padrão de "table1" para a primeira tabela.
Exemplos de utilização de um DataSet
Recursos usados nos exemplos a seguir:
1- Usando um DataSet com SqlDataAdapter para selecionar dados no SQL Server
Neste exemplo estamos apenas acessando o SQL Server 2005 e selecionando dados da tabela Products. Como não estamos alterando os dados não precisamos usar o objeto SqlCommandBuilder para preparar o DataSet para realizar tais operações.
- Crie um novo projeto no Visual C# com o nome uDataSet1 do tipo Windows Forms Application ;
- No formulário padrão form1.cs inclua um controle DataGridView - gdvProdutos e um controle Button - btnPreencheGrid ;
- Defina o namespace System.Data.SqlClient
- Declare as variáveis objetos que serão usadas no projeto:
//define os objetos SqlConnection, DataSet //SqlDataAdapter e o nome da tabela private SqlConnection conn;private SqlDataAdapter daProdutos;
private DataSet dsProdutos;
private const string tabela = "Produtos";
- Inclua o seguinte código no evento Click do controle Button:
private void
btnPreencheGrid_Click(object sender,
EventArgs e)
{ //chama a rotina para iniciar o dataset IniciaDados(); //exibe o dataset no controle datagridview - dgvProdutos dgvProdutos.DataSource = dsProdutos; dgvProdutos.DataMember = tabela; } |
- A rotina IniciaDados() possui o seguinte código:
// definição dos objetos dataset,
sqldataadapter e sqlcommandbuilder
public void
IniciaDados()
{ try { //instancia uma nova conexão usando a string de conexão //com o banco de dados Northwind do SQL Server 2005 Express conn = new SqlConnection("Server=MAC\\SQLEXPRESS;DataBase=Northwind;Integrated Security=SSPI");
dsProdutos = new DataSet(); // 2. inicia o SqlDataAdapte passando o comando SQL para selecionar codigo e nome // do produto e a conexão com o banco de dados daProdutos = new SqlDataAdapter("Select ProductID, ProductName from Products", conn);
// 3. preenche o dataset daProdutos.Fill(dsProdutos, tabela); } catch(Exception ex) { //se houver erro exibe a mensagem MessageBox.Show(ex.Message); } } |
O resultado obtido pode ser visto na figura abaixo:
2- Usando um DataSet com SqlDataAdapter para incluir, alterar e excluir dados no SQL Server
Vamos usar o exemplo anterior e incluir no formulário mais 3 botões de comandos para incluir, alterar e excluir dados da tabela Products;
Incluir - btnIncluir
Alterar - btnAlterar Excluir- btnExcluir |
Vamos definir a variável do codigo como do tipo String que irá armazenar o código do produto.
private String codigo = "";A seguir temos o código do botão - Listar Dados - que após obter a lista de produtos habilita os botões de comando:
private void btnPreencheGrid_Click(object sender, EventArgs e) { IniciaDados(); //exibe o dataset no controle datagridview - dgvProdutos dgvProdutos.DataSource = dsProdutos; dgvProdutos.DataMember = tabela; btnIncluir.Enabled = true; btnExcluir.Enabled = true; btnAlterar.Enabled = true; }
|
No evento Click do botão Incluir temos o código que inclui um novo registro na tabela Products. Estamos usando o método NewRow() e incluindo uma nova linha na tabela; Estou incluindo um produto com o nome Macoratti_
Estamos usando o procedimento básico para incluir dados em um dataset : criando uma nova linha e em seguida adicionando a coleção DataRow do DataTable no DataSet
No nosso caso estamos fazendo isso em um DataSet não tipado chamando o método NewRow para criar uma nova linha vazia; esta linha herda a estrutura da coluna da coleção DataColumnCollection. Em seguida incluímos(add) a linha na coleção de linhas e atualizamos(update) o dataset.
private void btnIncluir_Click(object sender, EventArgs e) { daProdutos = new SqlDataAdapter("SELECT ProductID, ProductName FROM Products", conn); SqlCommandBuilder cmdbldr = new SqlCommandBuilder(daProdutos); dsProdutos = new DataSet(); daProdutos.Fill(dsProdutos); DataRow registro = dsProdutos.Tables[0].NewRow(); registro["ProductName"] = "Macoratti_"; dsProdutos.Tables[0].Rows.Add(registro); //atualiza o dataset daProdutos.Update(dsProdutos); MessageBox.Show("Registro incluido."); }
|
O código do evento Click do botão Alterar é visto a seguir.
- No código obtemos o valor do código do produto a
partir da linha selecionada no DataGridView e armazenamos na variável
codigo;
- Em seguida verificamos se o codigo possui um valor válido;
- Usamos o método Find do DataTable para localizar o registro com o
código obtido e atualizamos o nome do produto com um sinal de #;
private void btnAlterar_Click(object sender, EventArgs e) { daProdutos = new SqlDataAdapter("SELECT ProductID, ProductName FROM Products order by ProductID", conn); SqlCommandBuilder cmdbldr = new SqlCommandBuilder(daProdutos); dsProdutos = new DataSet(); daProdutos.Fill(dsProdutos); DataColumn[] chave = new DataColumn[1]; chave[0] = dsProdutos.Tables[0].Columns[0]; dsProdutos.Tables[0].PrimaryKey = chave; codigo = dgvProdutos.CurrentRow.Cells["ProductID"].Value.ToString(); if (codigo != null || !codigo.Equals("")) { DataRow registro = dsProdutos.Tables[0].Rows.Find(codigo); registro["ProductName"] = registro["ProductName"] + " # "; daProdutos.Update(dsProdutos); MessageBox.Show("Registro alterado."); } else { MessageBox.Show("Registro não localizado."); } } |
O código do evento Click do botão Excluir é visto a seguir.
- No código obtemos o valor do código do produto a
partir da linha selecionada no DataGridView e armazenamos na variável
codigo;
- Em seguida verificamos se o codigo possui um valor válido;
- Usamos o método Find do DataTable para localizar o registro com o
código obtido;
- Para excluir usamos o método Delete;
private void btnExcluir_Click(object sender, EventArgs e) { daProdutos = new SqlDataAdapter("SELECT ProductID, ProductName FROM Products order by ProductID", conn); SqlCommandBuilder cmdbldr = new SqlCommandBuilder(daProdutos); dsProdutos = new DataSet(); daProdutos.Fill(dsProdutos); DataColumn[] chave = new DataColumn[1]; chave[0] = dsProdutos.Tables[0].Columns[0]; dsProdutos.Tables[0].PrimaryKey = chave; codigo = dgvProdutos.CurrentRow.Cells["ProductID"].Value.ToString(); if (codigo != null || !codigo.Equals("")) { DataRow registro = dsProdutos.Tables[0].Rows.Find(codigo); registro.Delete(); daProdutos.Update(dsProdutos); MessageBox.Show("Registro excluido."); } else { MessageBox.Show("Registro não localizado."); } } |
O resultado obtido pode ser visto na figura abaixo:
Com isso mostrei os procedimentos básicos de como atualizar um dataset não tipado usando ADO .NET;
Pegue o projeto completo aqui : uDataSet1.zip
No próximo artigo irei falar mais um pouco sobre dataset , mais particularmente dos datasets tipados.
Eu sei é apenas C# e ADO .NET, mas eu gosto...
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
|
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#