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
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
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
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
// 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.