msdn30_capa.jpg

Clique aqui para ler todos os artigos desta edição

Criando uma camada genérica de acesso a bancos de dados

Rogério Moraes de Carvalho

Este artigo discute

Este artigo usa as seguintes tecnologias

·        Acesso a diferentes bancos de dados usando o mesmo código: SQL Server, DB2, MySQL e Firebird;

·        Desenvolvimento em camadas;

·        Fábricas para criação de objetos.

 

C# 2.0, Visual Studio 2005, SQL Server 2005, Firebird, DB2 e MySQL.

 

O ADO.NET fornece um acesso consistente a fontes de dados variadas, permitindo a realização de operações de recuperação, manipulação e atualização de dados. Apesar das versões 1.0 e 1.1 do ADO.NET (ADO.NET 1.x) serem baseadas em interfaces e classes abstratas, uma implementação de acesso a dados independente de fornecedor é de inteira responsabilidade do desenvolvedor.

O ADO.NET 2.0 fornece avanços significativos em diversas áreas, inclusive tendo introduzido novas classes que funcionam como fábricas para criação de objetos genéricos para acesso a dados. O objetivo deste artigo é explorar essas classes para criar uma camada genérica de acesso a bancos de dados relacionais. No decorrer do artigo, por uma questão de simplicidade, toda vez que for citado o termo “camada de acesso a dados”, deve-se entender que se trata de uma “camada genérica” de acesso a bancos de dados relacionais.

Durante o artigo será produzida uma solução no Visual Studio 2005, completamente funcional e desenvolvida com a linguagem C# 2.0 (acompanha os códigos fontes, uma versão em Visual Basic 2005), composta por um projeto de componente Class Library com o modelo de negócios, um outro projeto de componente Class Library com a camada de acesso a dados e um ASP.NET Web Site com a camada de apresentação, sendo que esse último é composto por uma interface web simples para gerenciamento de inscrições em um evento. O objetivo dessa solução é ilustrar os principais conceitos apresentados na parte teórica do texto.

A aplicação web permitirá que o desenvolvedor alterne o acesso entre diferentes bancos de dados com uma simples modificação num arquivo web.config. Os bancos de dados utilizados para testar a solução desenvolvida neste artigo foram: SQL Server 2005 Developer Edition com Service Pack 1, IBM DB2 Express-C 8.2.4, Firebird 1.5.3 e MySQL 5.0.21 Community Edition.

Porém, o leitor pode direcionar a aplicação para utilizar qualquer outro banco de dados, desde que sejam satisfeitas as seguintes condições: o esquema de objetos do banco de dados deve ser compatível com o descrito no artigo e deve existir pelo menos uma implementação de um provedor de dados para o .NET Framework 2.0, voltado para o banco escolhido, que suporte todas as operações desenvolvidas na camada de acesso a dados da solução.

Algum banco de dados relacional pode não ter disponível um provedor de acesso a dados gerenciado para o .NET Framework 2.0, mas sim um OLE DB Provider ou um driver ODBC. Nesse caso, deve-se dar preferência ao OLE DB Provider e, em último caso, ao driver ODBC. A Microsoft fornece provedores de dados .NET para ambos com o .NET Framework 2.0 nos namespaces System.Data.OleDb e System.Data.Odbc, respectivamente.

Pré-requisitos para a leitura deste artigo

Para um bom aproveitamento das informações expostas neste artigo, é recomendado que o leitor tenha conhecimentos em SQL, noções básicas de pelo menos dois servidores de bancos de dados relacionais, POO com C# 2.0, familiaridade com as principais classes de acesso a dados do ADO.NET e noções básicas de desenvolvimento web com ASP.NET. Opcionalmente, conhecimento básico do padrão de projeto Abstract Factory da Gang of Four (GoF).

Os softwares necessários para criar o exemplo são citados a seguir. Sistema operacional: Windows 2000, Windows XP ou Windows Server 2003, com os Services Packs necessários. Bancos de dados: pelo menos dois dos servidores de BDs citados na introdução ou algum outro que tenha disponível alguma implementação funcional de provedor de dados para o .NET Framework 2.0. Provedores de dados para o .NET Framework 2.0: Devem ser instalados provedores de dados funcionais para o .NET Framework 2.0 para os BDs instalados. Ambiente de desenvolvimento: Visual Studio 2005 (qualquer edição) ou Visual C# 2005 Express Edition, para o desenvolvimento de Class Library, e Visual Web Developer 2005 Express Edition, para desenvolvimento de ASP.NET Web Site.

 

Nota: A seção Links apresenta os endereços de sites com informações das versões mais recentes dos softwares abordados, detalhes sobre os padrões de projeto citados e outras informações relacionadas com o artigo. Portanto, nenhum link será colocado no meio do texto.

Classes de provedores de fábricas para acesso a dados

O padrão de projeto Abstract Factory da Gang of Four (GoF) foi utilizado no .NET Framework 2.0 para fornecer uma interface para a criação de famílias de objetos para acesso a dados sem especificar as suas classes concretas. A nova classe abstrata DbProviderFactory, do namespace System.Data.Common, representa uma fábrica com um conjunto de métodos virtuais, portanto polimórficos, para criar instâncias de classes de uma implementação de fonte de dados específica. Cada provedor de dados projetado para o .NET Framework 2.0 deve fornecer uma especialização da classe abstrata DbProviderFactory. A Figura 1 mostra um esquema simplificado de classes para acesso a dados no ADO.NET 2.0.

image002.gif

Figura 1. Esquema simplificado de classes para acesso a dados no ADO.NET 2.0

De um modo geral, mas com algumas exceções, interfaces nomeadas como IDb* (IDbConnection, IDbCommand, IDbDataAdapter etc.), do namespace System.Data, são implementadas por classes abstratas nomeadas como Db* (DbConnection, DbCommand, DbDataAdapter etc.), do namespace System.Data.Common. As classes abstratas Db* implementam alguns métodos das interfaces correspondentes IDb* e passam a responsabilidade de implementação de outros métodos para classes concretas desenvolvidas em provedores de dados para o .NET Framework 2.0. Conforme a descrição do padrão de projeto Abstract Factory, as classes abstratas declaram uma interface para um tipo de objeto-produto.

Os quatros retângulos na parte inferior esquerda da Figura 1 representam os provedores de dados fornecidos com o .NET Framework 2.0, enquanto que os outros dois correspondem a provedores de dados fornecidos por terceiros. Os provedores de dados do Grupo 1 fornecem fábricas que são especializações da classe DbProviderFactory. Já os provedores do Grupo 2 não fornecem essa implementação, como ocorre com os provedores de dados projetados para o .NET Framework 1.x.

Arquitetura da aplicação de demonstração

A adoção de uma arquitetura multicamadas em uma aplicação pode aumentar a complexidade inicial de um projeto, porém essa separação permite um desenvolvimento modular, facilita a reutilização, aumenta a flexibilidade a mudanças de requisitos e minimiza os impactos em futuras evoluções, dentre outras vantagens.

Uma boa arquitetura deve respeitar a separação de camadas, impedindo o uso de recursos em uma camada que gere dependência de outra. A camada de acesso a dados é responsável pelas operações de leitura e escrita em uma fonte de dados, geralmente um banco de dados, sendo estritamente proibido o uso de uma API de acesso a dados, como o ADO.NET, em outras camadas.

Existem algumas soluções para encapsular o acesso a dados numa camada separada. O padrão de projeto Data Access Object (DAO), fornece uma API uniforme aos clientes de forma independente da fonte de dados utilizada. O padrão DAO oculta completamente os detalhes de acesso a dados dos seus clientes.

É indicado o uso de outro padrão de projeto, denominado Transfer Object, para transportar dados entre os objetos DAO e o cliente. Porém, uma explicação detalhada do uso desses padrões de projeto estenderia demasiadamente o artigo e o código da aplicação de demonstração.

Uma aplicação simples para gerenciamento de inscrições em um evento será desenvolvida para ilustrar o uso do modelo independente de provedor incorporado ao ADO.NET 2.0, que foi explicado na seção anterior. A arquitetura simplificada da aplicação é apresentada na Figura 2.

 

image004.jpg

Figura 2. Arquitetura simplificada de uma aplicação para gerenciamento de inscrições num evento

A camada de acesso a dados será desenvolvida com os recursos do ADO.NET 2.0 para oferecer acesso genérico a bancos de dados relacionais, sendo que nessa demonstração a camada será testada com os banco indicados na introdução.

A camada de apresentação será desenvolvida com recursos do ASP.NET 2.0, fornecendo uma interface simples com o usuário para o gerenciamento das inscrições num evento. O modelo de negócios conterá uma única classe denominada Inscricao.

Criação e população dos bancos de dados

As estruturas dos bancos de dados devem ser equivalentes, o máximo possível, para que a camada de acesso a dados genérica funcione corretamente. Em cada servidor será criado um banco de dados nomeado “Evento”, com uma tabela nomeada “Inscricao”, contendo os seguintes campos obrigatórios: InscricaoID do tipo inteiro e com numeração automática - chave primária, NomeCompleto do tipo texto variável com tamanho máximo de 100 caracteres, Email do tipo texto variável com tamanho máximo de 50 caracteres e DataHora do tipo data/hora.

SQL Server 2005

Em qualquer edição do SQL Server 2005, 2000 ou 7.0, use uma ferramenta cliente como o SQL Server Management Studio (SQL Server 2005), o Query Analyzer (SQL Server 2000 ou 7.0) ou outra ferramenta cliente para criar o banco de dados Evento e executar um script SQL para criar e popular a tabela Inscricao.

A criação do banco de dados Evento pode ser realizada pela execução da seguinte instrução SQL “CREATE DATABASE Evento;” ou com uso de comandos da interface gráfica com o usuário de uma ferramenta cliente. Depois, a mudança para o contexto do banco de dados Evento pode ser feita pela instrução “USE Evento;”. Então, basta executar o script SQL apresentado na Listagem 1 para criar e popular a tabela Inscricao no banco de dados.

 

Listagem 1. Script SQL para criação e população da tabela Inscricao no SQL Server

CREATE TABLE Inscricao (

   InscricaoID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY

   , NomeCompleto VARCHAR(100) NOT NULL

   , Email VARCHAR(50) NOT NULL

   , DataHora SMALLDATETIME NOT NULL

);

 

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('João da Silva', 'joaos@sqlserver.xyz.br',

  '2006-05-01 8:15');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('Maria Pereira', 'mariap@sqlserver.xyz.br',

  '2006-05-01 9:10');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('José Lima', 'josel@sqlserver.xyz.br',

  '2006-05-01 9:30');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('Ana Conceição', 'anac@sqlserver.xyz.br',

  '2006-05-01 10:22');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('Marta Bastos', 'martab@sqlserver.xyz.br',

  '2006-05-01 11:37');

 

MySQL 5.0

No MySQL 5.0.21, ou outra versão, utilize uma ferramenta cliente como o MySQL Query Browser, o MySQL Command Line Client ou outra ferramenta cliente para criar o banco de dados Evento e executar um script SQL para criar e popular a tabela Inscricao. A Listagem 2 apresenta um script completo. Nesse caso, o script cria o banco de dados Evento e muda para o seu contexto, depois cria e insere cinco registros na tabela Inscricao.

 

Listagem 2. Script SQL para criação do banco Evento e da tabela Inscricao no MySQL

-- Criação do banco de dados Evento

CREATE DATABASE Evento;

 

-- Mudança do contexto para o banco Eventos

-- para execução das próximas instruções SQL

USE Evento;

 

-- Criação da tabela Inscricao no banco Evento

CREATE TABLE Inscricao (

  InscricaoID INTEGER NOT NULL

    AUTO_INCREMENT PRIMARY KEY

  , NomeCompleto VARCHAR(100) NOT NULL

  , Email VARCHAR(50) NOT NULL

  , DataHora DATETIME NOT NULL

);

 

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('João da Silva', 'joaos@mysql.xyz.br',

  '2006-05-01 8:15');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('Maria Pereira', 'mariap@mysql.xyz.br',

  '2006-05-01 9:10');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('José Lima', 'josel@mysql.xyz.br',

  '2006-05-01 9:30');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

  VALUES ('Ana Conceição', 'anac@mysql.xyz.br',

  '2006-05-01 10:22');

INSERT INTO Inscricao (NomeCompleto, Email, DataHora)

...

Quer ler esse conteúdo completo? Tenha acesso completo