## Capítulo 6. Iniciando com o ADO.NET

NESTE CAPÍTULO

- ### A Importância ADO.NET

- Construindo uma Aplicação Simples com ADO .NET

- Objetos Para Dados Desconectados

- Comparando ADO e ADO.NET

ADO.NET é a nova tecnologia da Microsoft para acessar dados. A Microsoft já vem a muito tempo na linha de frente do movimento de acesso universal a dados, iniciando com a Open Data Base Connectivity (ODBC) a quase nove anos atrás. Não há dúvidas sobre a importância de acesso a dados para aplicações modernas, mas o modo como você acessa os dados tem um impacto significativo na performance e escalabilidade da aplicação. Some-se a isto o fato de que as aplicações estão crescendo na sua distribuição, e a passagem de grandes quantidades de dados de um lugar para outro torna-se uma questão ainda mais crítica no design e criação de aplicações.

A Microsoft tem dedicado um bocado de trabalho no acesso a dados. Ela tem realizado um grande número de mudanças na tecnologia de acesso a dados, e o ADO .NET não é outra coisa senão mais um destes avanços. Os desenvolvedores descobrirão toda uma nova forma de criar aplicações orientadas para banco de dados. Combinando o poder acesso a dados, XML e da .NET Framework, a Microsoft apresentou sua mais poderosa tecnologia de acesso a dados até hoje.

### A Importância do ADO.NET

O mundo das aplicações vem evoluindo a algum tempo. Inicialmente, as aplicações eram centralizadas, e eram acessadas por terminais burros. Todo o código rodava no mainframe, e os profissionais de tecnologia da informação (IT) controlavam tudo.

Com o tempo surgiu o PC e tudo mudou. O poder de computação moveu-se para a mesa de trabalho e as pessoas passaram a executar planilhas, bancos de dados, processadores de texto e outras coisas mais. Contudo, nenhum PC podia ser uma ilha por muito tempo. Logo, as pessoas estariam ligando de volta seus PCs com cordões umbilicais a servidores, naturalmente, aqueles mainframes.

Dado que os PCs estavam constantemente sendo ligados a servidores, você viu surgir a computação Cliente/Servidor. Diferentemente da abordagem centralizada das aplicações mainframe/terminal burro, você tinha uma solução distribuída na qual os dados ficavam no servidor e muito da funcionalidade rodava no cliente.

Em seguida, veio o desenvolvimento n-camadas, no qual as regras de negócio estavam postas em objetos centralizados rodando no servidor. Isto significou que as aplicações clientes eram usadas para tarefas como recebimento de entrada, exibição de dados, impressão e por aí adiante. Regras de negócios e acesso a dados foram encapsulados em componentes compartilhados, reutilizáveis, que acessavam dados em um banco de dados localizado em um micro potente ou em um mainframe

No passo seguinte da evolução, as aplicações Web tornaram-se a moda, e logo o desenvolvimento retornou ao modelo centralizado dos tempos dos mainframes. O navegador estava atuando como nada mais do que um terminal burro, aceitando entradas do usuário e exibindo telas. Todo o processamento ocorria sob o controle do departamento de tecnologia da informação, e era distribuído por servidores Web, servidores de aplicação e servidores de bancos de dados.

Embora aplicações Web ainda sejam comuns, muitas delas estão sendo desenvolvidas usando o modelo n-camadas. Mais importante é que o aparecimento de uma nova classe de componentes, chamados Web Services, está mudando o modo como as aplicações são desenvolvidas. Com Web Services, você pode usar a Internet como um sistema operacional distribuído, com componentes localizados em qualquer parte do mundo e acessados via HTTP. Você verá mais sobre Web Services no capítulo 9, "Criando Web Services com VB .NET".

É neste mundo que o ADO .NET surge, pronto para enfrentar o desafio de ter componentes que, embora, distribuídos pela Internet, ainda precisam passar dados de um para o outro. Algumas partes do ADO.NET são muito mais simples que as correspondentes nas tecnologias que o antecedem. Algumas facetas do ADO.NET podem parecer bem complexas, mas isto costuma ser devido a um nível de indireção almejado para tornar o acesso a dados mais lógico nos ambientes dos nossos dias.

Para melhor entender o ADO.NET, é útil compreender como ele evoluiu. Prepare-se para uma breve lição de história e você entenderá melhor o porquê do nascimento do ADO.NET.

### A Árvore da Família ADO.NET

ADO.NET é a mais recente de uma linha de tecnologias de acesso a dados da Microsoft. Mesmo sendo um passo na evolução, é um grande passo para frente; pode ser considerado a maior mudança no acesso a dados da Microsoft desde o seu primeiro modelo de objetos lançado a dez anos atrás. ADO.NET representa a primeira vez que a Microsoft tentou separar o conceito de acesso a dados do conceito de manipulação dos dados, como será visto nas seções seguintes.

### No Princípio: SQL Embutido e APIs

No início, as aplicações acessavam dados pelo simples embutimento de comandos SQL no programa, juntamente com toda a informação necessária para acessar o banco de dados. Muitas aplicações mainframe criadas antes de 1990 tinham acesso direto ao banco de dados pelo programa. Eles continham informações de conexão, comandos SQL para acessar e manipular dados e código para exibir os dados. Estas aplicações fortemente ligadas aos dados, pressupunham a constância do nome do servidor e do banco de dados. Em adição, qualquer mudança na estrutura de tabelas costumava exigir a recompilação das aplicações clientes.

Para abrir os bancos de dados a uma forma alternativa de acesso, APIs próprias para bancos de dados foram criadas, tais como a DB-Lib e OCL. Estas APIs foram feitas para permitir que os desenvolvedores, quase sempre em C, acessassem os dados de uma máquina Unix ou Windows. Estas bibliotecas eram tipicamente rápidas por serem otimizadas para um banco de dados específico. Contudo, elas eram difíceis de usar; eram APIs de baixo nível e não baseadas em objetos como as tecnologias posteriores viriam a ser. Em adição, porque elas eram específicas para um banco de dados, tornava-se muito difícil mudar de um banco de dados para outro. Para fazer a mudança, uma grande parte da aplicação teria que ser reescrita para usar uma biblioteca completamente nova.

### ODBC, DAO, e RDO

Quando a Microsoft lançou o Access 1.0 nos anos noventa, era seu primeiro programa de banco de dados para Windows. O Access continha o JET database engine, que era o dispositivo de acesso a dados para aplicações desktop da Microsoft (assim como o SQL Server é o seu dispositivo de banco de dados servidor). A Microsoft viu que, embora o JET fosse bom para a criação de aplicações baseadas no armazenamento de dados em um PC, nem todos os dados eram armazenados em um PC. Muitas companhias já tinham dados armazenados em bancos de dados servidores como SQL Server, Oracle e DB2. A Microsoft, portanto, queria que as pessoas não só tivessem acesso a estes dados em servidor, mas pudessem usá-los com a mesma facilidade que usavam os dados armazenados pelo JET. Para atingir isto, em 1993, a Microsoft lançou a Open Database Connectivity ou ODBC.

ODBC, diferente das APIs específicas de bancos de dados, permitia que o desenvolvedor programasse de tal forma que o banco de dados físico tornasse-se menos importante que a estrutura lógica do esquema. Você poderia escrever seus comandos SQL e, se fossem apenas SQL padrão, você poderia mudar o dispositivo de acesso a dados sem ter que reescrever parte alguma do seu código. Isto era porque a ODBC tinha um nível de indireção entre a sua aplicação e o banco de dados. Você apontava para algo chamado de data source name, ou DSN. O DSN determinava qual banco de dados você estaria acessando ( pelo carregamento do driver de ODBC apropriado) e a localização do banco de dados.

ODBC foi projetada para, não só permitir que você acessasse os dados, mas fazer os dados remotos parecerem locais. As tabelas remotas pareciam como as tabelas locais do JET a ponto de você poder criar consultas SQL juntando tabelas locais do JET com tabelas remotas. Ou, você poderia realizar joins em tabelas de diferentes bancos de dados remotos, como realizar joins entre tabelas do SQL Server e tabelas do Oracle usando ODBC e o JET como uma camada intermediária.

No JET, a Microsoft também incluiu um modelo de objetos chamado Data Access Objects, ou DAO. O DAO continha um conjunto de classes que permitiam-lhe acessar facilmente bancos de dados, tabelas, registros e outros objetos de bancos de dados. Para qualquer tabela, você poderia examinar as colunas, incluindo os nomes das colunas, tipos e etc. Você podia usar comandos da linguagem de definição de dados (DDL) para criar ou excluir tabelas, criar ou excluir índices e assim por diante.

O JET fez sucesso entre os desenvolvedores, porque ele apresentava aos desenvolvedores um rico conjunto de objetos fáceis de usar com os quais se poderia acessar e manipular dados. Os desenvolvedores usando Access ou Visual Basic poderiam usar DAO para trabalhar com qualquer dado em banco de dados JET, incluindo aquelas tabelas ligadas ao banco de dados JET via ODBC. Isto significou que os desenvolvedores tinham fácil acesso aos dados não importando o banco de dados real em que eles estivessem armazenados.

O problema com o DAO, contudo, era que ele foi criado baseado no JET. E se todos os seus dados estivessem em SQL Server, ou Oracle, ou algum outro tipo de banco de dados? Você poderia ligar todas as tabelas ao banco de dados JET via ODBC e usar DAO, mas então você teria o JET entre você e seus dados, O JET era relativamente grande nesta época, consumindo perto de 1 MB de memória numa época em que as máquinas tipicamente tinham de 4 a 16 MB de RAM. Em adição, o JET incluía um otimizador de consultas, que já estava disponível nos bancos de dados servidor. Todas as consultas ao banco de dados servidor tinham que passar pela camada do JET, incluindo pelo seu otimizador de consultas, e novamente pelo otimizador do servidor. O resultado era que a passagem pelo DAO e JET poderia ser lenta.

Uma alternativa ao uso do DAO era programar diretamente com ODBC. Este era um modo muito mais rápido de acessar dados, mas era muito mais difícil. ODBC não era baseada em objetos, como o DAO. Portanto, programar com a API de ODBC requeria significativamente mais código, e elementos tais como o cursor de banco de dados e mesmo memória tinham que ser gerenciados pelo programador.

Por um bom tempo, os desenvolvedores que acessavam dados em servidores tinham estas duas opções: usar DAO, que era fácil, mas (relativamente) lento, ou programar com a API de ODBC, que era rápida mas difícil.

A Microsoft reconheceu que deveria haver um modo melhor e, no lançamento do Visual Basic 4.0, em 1995, a Microsoft também lançou um novo modelo de objetos, baseado na ODBC, chamado Remote Data Objects ou RDO. RDO era muito parecido em estrutura com o DAO, mas muitos dos nomes de objetos eram diferentes o bastante para exigir que o código em DAO tivesse de ser reescrito. Porém, os conceitos básicos eram os mesmos, tais como conectar-se a um banco de dados, ter acesso a coleções de tabelas, e então a coleções de campos e assim por diante. O modo de acessar dados era parecido entre DAO e RDO, mas RDO não tinha que usar o JET, de modo que você tinha quase a mesma velocidade de ODBC com a facilidade de programação que já tinha apenas no DAO.

A Microsoft tinha DAO e RDO, ambos baseados em ODBC. Estes eram os dois modelos de objetos que os desenvolvedores estavam usando com grande sucesso. Contudo, a Microsoft viu uma nova tendência de mercado, e decidiu acompanhá-la com uma nova tecnologia: OLE DB.

### OLE DB e ADO

A Microsoft criou a ODBC com uma inclinação particular: ela assume um modelo relacional de armazenamento de informações. Entenda que, embora hajam drivers de ODBC para arquivos Excel, arquivos texto e outras fontes não relacionais, estes drivers fazem a fonte parecer relacional. DAO e RDO foram projetados com uma estrutura relacional em mente; quando você conecta-se a um banco de dados, ele automaticamente preenche uma coleção de tabelas disponíveis. Cada tabela tem uma coleção de colunas que é automaticamente preenchida. Estas coleções e objetos são disponibilizadas porque é assumido que a fonte é um banco de dados relacional.

A Microsoft sabia que nem todos os dados de uma corporação são armazenados em bancos de dados relacionais. Por exemplo, dados corporativos pode estar armazenados no Exchange ou no Active Directory, nenhum dos quais usa um dispositivo relacional. Dados podem estar armazenados em arquivos Excel ou texto, ou uma variedade de outros formatos. A Microsoft queria projetar um modo de ler dados tanto relacionais quanto não-relacionais usando uma metodologia consistente. Foi criada então a OLE DB.

OLE DB é uma API de baixo nível como a ODBC. Contudo, OLE DB não assume uma fonte relacional. Pelo contrário, OLE DB usa seus próprios drivers, chamados providers, para acessar os dados. Providers nativos de OLE DB permitem-lhe acessar dados relacionais ou não-relacionais usando a mesma API.

Embora OLE DB seja uma API de baixo nível, a Microsoft tinha aprendido com a sua experiência com a ODBC e RDO, de modo que a OLE DB foi lançada com o ActiveX Data Objects, ou ADO. ADO é o modelo de objetos fácil de usar construído sobre o topo da OLE DB. Usando ADO, você pode fazer uma conexão ao banco de dados e acessar registros. ADO permite-lhe usar um único conjunto de objetos para acessar fontes de dados não importando o formato dos dados.

Diferente do DAO e RDO, contudo, o modelo de objetos ADO é bem reduzido. DAO e RDO contêem ambos dúzias de objetos, enquanto ADO contém menos de dez objetos principais. DAO e RDO podem automaticamente preencher coleções de tabelas, colunas e relacionamentos. ADO não tem estes objetos porque ADO, sendo baseado na OLE DB, não pode automaticamente assumir um banco de dados relacional como a sua fonte. Portanto, com ADO, você tem que saber como consultar as tabelas do sistema para examinar sua estrutura.

Nota

A Microsoft realmete lançou um modelo de objetos acompanhante para o ADO chamado ADOX. ADOX assume uma fonte relacional e tem os necessários objetos para trabalhar com tabelas, colunas, relacionamentos, etc. Apesar disto, poucas pessoas chegam a usar ADOX.

Dado o fato de que a OLE DB não assume uma fonte relacional, ADO tem um pequeno número de objetos e, portanto, tem um baixo consumo de memória. Também é muito rápido; OLE DB providers tendem a superar em performance ao drivers de ODBC para um banco de dados.

ADO, nas suas mais recentes versões, também soma alguns recursos de XML. Por exemplo, você pode usar ADO para criar recordsets desconectados. Estes recordsets são armazenados em disco e você os pode abrir com ADO sem a necessidade de primeiro conectá-los a um banco de dados. Estes recordsets pode ser persistidos tanto em formato binário ou no formato XML. Estes recordsets desconectados podem ser usados para aumentar a performance da aplicação, porque, com eles, você não tem que manter uma dispendiosa conexão ao banco de dados para transmiti-los na rede. É possível mesmo fazer inclusões, alterações e exclusões nestes recordsets desconectados e depois sincronizar suas mudanças com o banco de dados.

A despeito desta capacidade de criar recordsets desconectados, ADO tipicamente assume um ambiente conectado onde você transfere registros do banco de dados para o cliente usando um dos diversos tipos de cursores. Embora ADO seja diferente de DAO e RDO, todos os três são construídos sobre um modelo conectado e combinam o acesso a dados com a manipulação dos dados. A diferença entre as duas ações é importante e será examinada na próxima seção.

Em adição, dados são tipicamente recuperados e armazenados na memória de forma que é fácil de acessar e manipular quando estão no processo da aplicação cliente. Contudo, se os dados são recuperados em uma camada intermediária e necessitam ser transferidos para o cliente para serem exibidos, é uma constante luta para descobrir a melhor forma de transferir os dados de uma camada para a outra. Passagem de dados entre processos é sempre um desafio com aplicações multicamadas. ADO.NET tenta responder a esta questão de separação do acesso a dados da exibição e manipulação dos dados, e também como passar dados entre camadas. Você pode ver a linha evolutiva das tecnologias de acesso a dados da Microsoft na figura 6.1.

Figura 6.1. A linha evolutiva das tecnologias de acesso a dados da Microsoft .

Por que Existe ADO.NET

Do mesmo modo como a Microsoft viu a necessidade de mover da ODBC para a OLE DB, ela viu a necessidade de ir além da OLE DB. Embora não haja nada de inerentemente errado com a ODBC ou OLE DB, a Microsoft viu que muitos dos esforços atuais de desenvolvimento são gastos criando sistemas n-camadas. Não só estas aplicações n-camadas foram criadas para rodar dentro da companhia, mas também podem querer utilizar um tipo específico de componente - serviços Web - que são expostos na Web via HTTP.

Graças a um iniciativa chamada de Simple Object Access Protocol, ou SOAP, é possível chamar componentes em qualquer parte na Web vic HTTP. SOAP é um protocolo baseado em XML criado para envio e recebimento de informação em um ambiente distribuído, habilitando chamadas de procedimentos remotos via HTTP. Com SOAP e serviços Web, você tem a vantagem adicional de independência de plataforma; o serviço Web pode ser escrito em C# e rodar em um servidor Windows XP, enquanto o cliente que o chama pode ser um serviço Web escrito em C++ rodando em um Linux, ou poderia ser um telefone habilitado para Web. A questão é que a chamada é apenas uma solicitação HTTP, e o retorno é dado em uma resposta HTTP com a solicitação e resposta real contendo XML.

A passagem de dados de um serviço Web para alguma forma de cliente mostra uma razão para a existência do ADO.NET. A passagem de um recordset ADO de um serviço Web para um cliente é possível, mas há certos inconvenientes. Primeiro, você tem de criar um cursor estático. Então, você tem de salvar o recordset em formato XML e enviá-lo de volta para o cliente. O formato padrão ADTG dos recordsets ADO é tipicamente instransferível através de firewalls ou servidores proxy; mesmo se o for, o formato binário ADTG terá pouco significado para uma aplicação cliente não-Windows. Portanto, ADO.NET, como você verá, fala XML nativamente.

Uma razão a mais para a existência do ADO.NET é o fato de que a Microsoft queria separar o acesso a dados do trabalho com os dados. Isto fornece um outro nível de indireção, e permite que você separe os objetos que lhe ajudam a trabalhar com dados dos objetos que o ajudam a acessar dados. Este novo nível também torna bastante simples trabalhar com dados desconectados por padrão, o que pode conduzir a grandes ganhos de escalabilidade.

Além disto, ADO. NET existe por causa da .NET Framework. No passado, ODBC e OLE DB, juntamente com seus modelos de objetos associados, eram independentes de qualquer ferramenta específica. Com a .NET Framework, a Microsoft introduziu o ADO.NET no conjunto padrão de serviços disponível para todas as linguagens que usam a .NET Framework. Agora, o acesso a dados torna-se um dos serviços básicos oferecidos pela infraestrutura de serviços, garantindo uma tecnologia de acesso a banco de dados consistente ao longo de todas as linguagens .NET.

Por ser criado dentro da .NET Framework, isto significa que o ADO.NET leva a vantagem de todos os serviços fornecidos pela Framework, tais como gerenciamento automático de memória, gargage collection, e assim por diante. Isto torna o ADO.NET fácil de manipular e significa que aqueles de vocês que escreverem código gerenciado em C++ não terão que se preocupar com o tratamento da memória usada pelo ADO.NET.

ADO.NET é diferente de DAO, RDO e ADO pelo fato de que ele não tem uma API subjacente como a OLE DB ou ODBC. Ao contrário, ADO.NET pode usar drivers nativos, chamados de provedores gerenciados, escritos para cada banco de dados, ou ele pode usar um provedor gerenciado genérico OLE DB que usa provedores OLE DB. Por haver um provedor de OLE DB para ODBC, isto significa que o ADO.NET pode usar seus provedores gerenciados, OLE DB ou ODBC. A melhor performance vem dos provedores gerenciados, como você pode imaginar. Os únicos provedores gerenciados no lançamento da .NET Framework eram para SQL Server 7.0/2000 e para OLE DB. Versões anteriores de SQL Server, ou qualquer outro banco de dados, necessitariam usar o provedor gerenciado de ADO.NET para OLE DB.

Arquitetura Desconectada do ADO.NET

Muito barulho se tem feito sobre a arquitetura desconectada do ADO.NET e ela é importante. Antes de mergulharmos nesta arquitetura desconectada, contudo, é importante entender que o ADO.NET também pode operar num modo conectado. ADO.NET usa diferentes objetos dependendo se você está operando em um modo conectado ou desconectado, e este paradigma permite que você identifique mais facilmente quando está usando um modo conectado em lugar de um desconectado. Em tecnologias de acesso a dados anteriores, você fazia uma conexão ao servidor e a mantinha aberta enquanto acessava e manipulava os dados. Tudo ia bem enquanto o número de clientes era pequeno, mas não tendia a escalar muito bem. Em adição, você abria uma conexão aos dados e podia às vezes navegar pelos dados, dependendo do cursor escolhido. Com algumas das opções de cursor do ADO, você podia realmente ler os valores de cada registro das tabelas subjacentes à medida que acessava os dados. Isto significava um bocado de idas e vindas ao banco de dados, e também significava que a única forma de obter boa performance era manter uma conexão em aberto.

Um truque que muitos usavam era criar um recordset desconectado no ADO. Isto podia ser alcançado pela leitura de todos os registros de uma vez e armazenando-os na memória do cliente naquilo que se chamava de um cursor estático. Você podia então gravar todo o recordset para um disco para persisti-lo ao longo do tempo. Você usava então esta cópia local dos dados ao invés de voltar ao banco de dados para buscar os dados. Esta abordagem funcionava muito bem para dados que não mudavam constantemente.

O ADO.NET armazena dados na memória em um modo inerentemente desconectado. Relembre-se de que o ADO.NET separa o acesso a dados do uso dos dados, o que significa que os conceitos de mover-se nos dados em um modo totalmente livre e realizar inclusões, atualizações e exclusões nada têm a ver com o ato físico de conectar-se ao banco de dados em si. Considere o ato de comprar e dirigir um automóvel. Toda manhã, quando você necessita dirigir-se para o escritório, você pega o seu carro e o dirige.Você não tem que ir ao revendedor antes de pegar seu carro. Pelo contrário, você pega seu carro uma só vez e o mantém em casa, e então você o dirige dali. Você usa seu carro desconectado do revendedor de quem você o comprou.

Do mesmo modo, ADO.NET permite que você conecte-se ao banco de dados e obtenha registros. Então, você se desconecta do banco de dados. Você continua a trabalhar com os registros, realizando ações como navegação pelos registros, ordenação e filtragem de registros e inclusões, alterações e exclusões.

Você pode estar dizendo, "Grande coisa. Eu posso fazer tudo isto com um recordset desconectado de ADO." Você está parcialmente correto, mas como você verá depois, ADO.NET fornece um novo objeto, chamado DataSet, que permite um nível inigualável de suporte desconectado. Por exemplo, se você estivesse usando um recordset desconectado de ADO e você inserisse um registro que violasse alguma regra de relacionamento, você não saberia desta violação até que você tentasse re-sincronizar o seu recordset desconectado com o banco de dados subjacente. O DataSet do ADO.NET, pelo contrário, pode garantir integridade referencial no modo desconectado, garantindo que você está seguindo as regras e fazendo alterações válidas nos dados.

ADO e outros modelos conectados podem também encontrar dificuldades na movimentação de dados de uma camada para outra. Se um componente na camada intermediária abrir uma conexão e iniciar a recuperação de dados, ele teria que alimentar registros para o cliente em uma string, em uma coleção, em uma matriz de variantes, passando um objeto recordset, ou por algum outro método. Cada método tende a ter seus prós e contras, e nenhum método é certo para todas as situações. Recordsets desconectados no ADO.NET, por outro lado, podem ser muito fáceis de passar de uma camada para outra (ou através de fronteiras de processos na mesma camada).

Não mantendo uma conexão aberta e tornando fácil e eficiente a passagem de dados através de fronteiras de processos, ADO.NET alcança um novo nível de escalabilidade.

Considerações Sobre Performance e Escalabilidade

(a ser continuado em breve)