Desenvolvimento - ADO.NET

A Classe DataSet e XML no ADO.NET

Neste artigo mostrarei a classe DataSet e sua integração com XML usando o Visual Studio.NET Beta 2. Você vai notar pelas imagens que estou usando o sistema operacional Windows XP. Não se preocupe, isto não é absolutamente necessário para que os programas funcionem.

por Mauro Sant'Anna



Neste artigo mostrarei a classe DataSet e sua integração com XML usando o Visual Studio.NET Beta 2. Você vai notar pelas imagens que estou usando o sistema operacional Windows XP. Não se preocupe, isto não é absolutamente necessário para que os programas funcionem.

A Classe DataTable(*) pode representar tabelas em memória, sem que tenha tido necessário acesso a um banco de dados tradicional em disco. Esta abstração é muito interessante porque facilita o trabalho com bancos de dados diferentes e também arquivos XML.

A idéia de representar tabelas em memória sem necessariamente ter acesso a um banco de dados físico é levada adiante na classe DataSet. A Classe DataSet pode conter várias tabelas e também relacionamentos entre as tabelas (“chave estrangeira”). Este esquema tem alguma semelhança com outras duas tecnologias mais antigas:

  • Propriedade “CachedUpdates” dos componentes TQuery e TTable do Delphi. Neste caso, o “buffer em memória” fica associado aos próprios componentes;
  • RecordSet desconectado usado na biblioteca Microsoft RDS.

As grandes vantagens do DataSet são:

  • Ele existe formalmente e pode ser facilmente manipulado;
  • Não depende de nenhum acesso físico a bancos de dados;
  • A integração com arquivos XML é fácil.

(*)A classe DataTable foi abordada em artigo anterior e sugerimos que o leitor se refira à revista de junho para maiores detalhes.

Criando um DataSet

O código a seguir cria duas tabelas, as adiciona a um DataSet e estabelece uma relação de “chave estrangeira” entre elas. Note também que as tabelas têm “chaves primárias”, impedindo a inserção de valores duplicados na coluna:

Listagem 1: Criando tabelas

DataTable CriaTabela1() {
// Cria uma nova tabela
DataTable Tbl = new DataTable("Usuarios");
// Adiciona os nomes e tipos das colunas
Tbl.Columns.Add("Codigo", typeof(int));
Tbl.Columns.Add("Nome", typeof(string));
Tbl.Columns.Add("EMail", typeof(string));
Tbl.Columns.Add("Endereco", typeof(string));
Tbl.Columns.Add("Aniversario", typeof(DateTime));
Tbl.Columns.Add("UF", typeof(string));
// Define a chave primária
Tbl.PrimaryKey = new DataColumn[] { Tbl.Columns["Codigo"] };
Tbl.Columns["Codigo"].AutoIncrement = true;
Tbl.Columns["Codigo"].AllowDBNull = false;
Tbl.Columns["Codigo"].ReadOnly = true;
// Adiciona dados
Tbl.Rows.Add(new object[]{null, "José Mané", "jose@mane.com", "R. da Pitangas, 40", new DateTime(1955, 3, 20), "SP"});
Tbl.Rows.Add(new object[]{null, "Mariquinha dos Anzóis", "mariquinha@anzois.com", "R. dos Trabucos, 8", new DateTime(1965, 4, 1), "SC"});
Tbl.Rows.Add(new object[]{null, "Abel das Traves", "abel@anzois.com", "R. dos Trabucos, 8", new DateTime(1965, 4, 1), "SC"});
return Tbl;
}
DataTable CriaTabela2() {
// Cria uma nova tabela
DataTable Tbl = new DataTable("Estados");
// Adiciona os nomes e tipos das colunas
Tbl.Columns.Add("UF", typeof(string));
Tbl.Columns.Add("Nome", typeof(string));
// Define chave primária
Tbl.PrimaryKey = new DataColumn[] { Tbl.Columns["UF"] };
// Adiciona dados
Tbl.Rows.Add(new object[]{"SC", "Santa Catarina"});
Tbl.Rows.Add(new object[]{"SP", "São Paulo"});
Tbl.Rows.Add(new object[]{"CE", "Ceará"});
return Tbl;
}
void MontaRelacao() {
// Define chave estrangeira
DS.Tables["Usuarios"].Constraints.Add("FK",
DS.Tables["Estados"].Columns["UF"],
DS.Tables["Usuarios"].Columns["UF"]);
}
// Declara o DataSet principal usado no programa
DataSet DS;
private void button1_Click(object sender, System.EventArgs e) {
// Cria um novo DataSet
DS = new DataSet();
// Acrescenta tabelas
DS.Tables.Add(CriaTabela1());
DS.Tables.Add(CriaTabela2());
// Monta relacionamento entre tabelas
MontaRelacao();
// Indica que as mudanças foram aceitas
DS.AcceptChanges();
// Exibe DataSet
dataGrid1.DataSource = DS;
groupBox1.Enabled = true;
}

Exibindo o DataSet

Quando exibimos o DataSet em um DataGrid, o DataGrid não “sabe” qual tabela deve ser mostrada. Por esta razão, é mostrado um sinal de mais, permitindo que seja escolhida a tabela a ser exibida:

Adicionando a tabela

Figura 1: Adicionando a tabela

Clicando-se no “+” aparece os nomes das tabelas presentes no DataSet:

Selecionando tabela

Figura 2: Selecionando tabela

Podemos então selecionar uma das tabelas clicando sobre seu nome, por exemplo “Usuarios”:

Tabela Usuários

Figura 3: Tabela Usuários

Caso desejemos voltar à visão anterior, basta clicar na seta no canto superior esquerdo do DataGrid:  Botão para voltar à visão anterior

Figura 4: Botão para voltar à visão anterior

É possível pedir a exibição de uma tabela em especial através de código:

Listagem 2: Exibindo tabela

private void button2_Click(object sender, System.EventArgs e) {
// Exibe tabelas Usuarios
dataGrid1.DataSource = DS.Tables["Usuarios"];
}

Alterando as tabelas

Note que é possível alterar a tabela diretamente no DataGrid. Experimente alterar valores e também inserir registros novos. Observe que o valor do campo “Codigo” é criado automaticamente:

 Adicionando a tabela

Figura 5: Adicionando a tabela

Não é possível entrar com um valor na coluna “UF” que não esteja presente na coluna “UF” da tabela “Estados”. Se você tentar fazê-lo, vai receber uma mensagem de erro como a seguinte:

Mensagem de erro

Figura 6: Mensagem de erro

Extraindo as mudanças

Todas as alterações feitas nas tabelas do DataSet podem ser extraídas para outro DataSet. Esta etapa é muito importante caso você deseje submeter as alterações em algum banco de dados.

As alterações podem ser extraídas com o método GetChanges, tanto do Dataset como do DataTable. Note que depois chamamos AcceptChanges para que o DataSet original “consolide” as alterações. O exemplo abaixo exibe as alterações em um outro DataGrid:

Listagem 3: Alterando uma tabela

private void button4_Click(object sender, System.EventArgs e) {
// Cria um novo DataSet
DataSet Modificados = new DataSet();
// Acrescenta tabelas modificadas
Modificados.Tables.Add(DS.Tables["Estados"].GetChanges());
Modificados.Tables.Add(DS.Tables["Usuarios"].GetChanges());
// Exibe alterações
dataGrid2.DataSource = Modificados;
// Aceita modificações
DS.AcceptChanges();
}

A classe DataSet também tem um método GetChanges, mas no caso acima temos um problema: por causa da chave estrangeira, teríamos problemas se alterássemos apenas a tabela Usuários, pois os registros alterados exigiriam uma chave estrangeira que não estaria disponível.

Integração com XML

O XML é um padrão para troca de dados entre diferentes sistemas. A grande vantagem do XML em relação às alternativas, como arquivos-texto, é que os dados estão descritos, tornando a troca de informações muito mais robusta, mesmo entre diferentes sistemas operacionais. Não é a minha idéia explicar como funciona o XML, mas simplesmente como o ADO.NET e a classe DataSet interagem com este padrão.

A principal classe da arquitetura .NET que trabalha com XML é a própria classe DataSet. Nela existem diversos métodos para manipular dados neste formato. Basicamente, você utilizará os métodosReadXML e WriteXML para ler e escrever dados no formato XML. Observe que cada um destes métodos é sobrecarregado várias vezes, dando uma grande liberdade para manipulação dos dados. Vejamos como ler e escrever em arquivos.

Escrevendo

Para escrever em um arquivo XML, use o método WriteXML. Observe que estamos especificando uma opção que escreve também informação da “estrutura” da tabela, também chamada “schema”: DS.WriteXml(@"c:\temp\teste.xml", XmlWriteMode.WriteSchema); Veja um trecho do arquivo escrito:

Trecho do arquivo XML

Figura 7: Trecho do arquivo XML

Lendo

Para ler o arquivo usaremos o método ReadXML em um DataSet novo:

Listagem 4: Lendo um arquivo

// Cria um novo DataSet
DS = new DataSet();
// Lê arquivo XML
DS.ReadXml(@"c:\temp\teste.xml <file:///C:tempteste.xml>");
// Exibe DataSet
dataGrid1.DataSource = DS;
groupBox1.Enabled = true;
Observe que podemos especificar uma URL como “nome de arquivo”. Neste caso, o arquivo XML será trazido da Web:
DS.ReadXml(@"http://localhost/teste.xml");

Conclusão

A classe DataSet permite uma enorme flexibilidade na manipulação de bancos de dados em memória e integração com arquivos XML.

Mauro Sant'Anna

Mauro Sant'Anna - Mauro tem mais de 20 anos de experiência no desenvolvimento de software, com produtos publicados no Brasil, Portugal e Estados Unidos, além de extensa experiência em treinamento e consultoria no desenvolvimento de software, tanto criando material como ministrando cursos.
Mauro é um "Microsoft Most Valuable Professional" (MVP - www.microsoft.com/mvp), “Microsoft Regional Director” (RD - www.microsoft.com/rd), membro do INETA Speaker’s Bureau (www.ineta.org) e possui as certificações MCP, MCSA (Windows 2000/2003), MCAD (C# e VB), MCDBA, MCSE (Windows 2000/2003).
Sua empresa, a M. A. S Informática (www.mas.com.br), treinou centenas de turmas em desenvolvimento de software nos últimos anos.