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'AnnaNeste 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 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:

Figura 1: Adicionando a tabela
Clicando-se no “+” aparece os nomes das tabelas presentes no DataSet:

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

Figura 3: Tabela Usuários
Caso desejemos voltar à visão anterior, basta clicar na seta no canto superior esquerdo do DataGrid:
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
1 2 3 4 | 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:

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:

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
1 2 3 4 5 6 7 8 9 10 11 | 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:

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
1 2 3 4 5 6 7 8 9 | // Cria um novo DataSet DS = new DataSet(); // Lê arquivo 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: |
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.