Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

RSS iMasters

[Resolvido] .NET: O acesso a dados usando um ORM - Entity Framewo

Recommended Posts

Quando o foco principal é o acesso a dados, a maneira como você se comunica com o banco de dados e o modo como representa esses dados na sua aplicação pode determinar o sucesso, ou o fracasso, do seu projeto.

Nesse assunto temos muitas opções, a começar com a utilização de objetos ADO .NET, como connections, adapters, readers e datasets. Essa abordagem é simples e fácil de ser entendida e permite que você tenha um desenvolvimento bem rápido.

Outra opção é utilizar classes ADO .NET para interagir com o banco de dados e, então, criar suas próprias classes (modelo de objetos) para representar os dados na sua aplicação. A curva inicial com tal modelo é maior, se comparada com a primeira, mas a longo prazo esta abordagem garante uma alta manutenção.

Uma terceira opção a ser considerada é utilizar uma ferramenta ORM, que esconde a complexidade de usar as classes ADO .NET e permite que você trabalhe somente com objetos em sua aplicação. Uma ferramenta ORM inclui o melhor das duas opções citadas acima, porque ela oferece uma produtividade imediata.

Mapeamento do objeto-relacional (ou ORM, do inglês: Object-relational mapping) é uma técnica de desenvolvimento utilizada para reduzir a impedância da programação orientada aos objetos, utilizando bancos de dados relacionais. As tabelas do banco de dados são representadas através de classes e os registros de cada tabela são representados como instâncias das classes correspondentes.

Considerando a plataforma .NET, a Microsoft criou a ferramenta ORM - conhecida como Entity Framework - adotando-a como a melhor prática para o acesso a dados. Dessa forma, vamos considerar apenas o Entity Framework, que atualmente esta na versão 4.1, para utilização em projeto com acesso a dados.

Com isso em mente, temos que compreender que o acesso a dados usando o Entity Framework é de vital importância, pois é partir de sua utilização que iremos nos apoiar para desenvolver nossas aplicações com acesso a dados.

Projetando uma aplicação com acesso a dados

Como exemplo, vamos criar uma aplicação que trata os pedidos para o banco de dados Northwind, onde temos dados sobre clientes e produtos armazenados nas tabelas: Orders, Customers, Order Details e Products. Abaixo, uma figura mostra essas tabelas no banco de dados:

45116.gif

Para começar, precisamos criar o nosso modelo de objetos, que são classes que tratam os dados e que são preenchidas com as informações a partir do banco de dados. Essas classes também precisam tratar os dados que atualizam o banco de dados.

Para o nosso exemplo, vamos criar as classes Order, Customer, Order_Detail e Product que conterão as propriedades que representam os dados no banco de dados e que serão úteis para o negócio. Essas classes escondem a complexidade da estrutura do banco de dados a partir do código de negócio, também conhecido como camada de negócios ou Bussines Logic Layer (BLL), permitindo que o código se comunique somente com elas e com uma camada específica, que será responsável por interagir com o banco de dados (Data Access Layer ou DAL).

A camada de lógica de negócios não sabe nada sobre o banco de dados e interage apenas com as quatro classes. A DAL é responsável por se comunicar com o banco de dados e com isso, as classes que criamos se tornam-se a camada de negócio do banco de dados da camada Lógica.

45117.gifA BLL usa as classes no modelo e então persiste as modificações via DAL. O código da BLL não sabe se conectar com um banco de dados.

A separação do código dentro de camadas isoladas é uma técnica que garante um desenvolvimento mais rápido e, talvez, mais importante, assim como uma manutenção mais fácil. Até o momento, já dissemos que o modelo contém classes que, por sua vez, contêm dados que são persistido no banco.

Mas como você deve fazer um modelo? Quais as técnicas que você precisa usar para construí-lo? A resposta é: depende.

O que é um modelo de objeto?

Em muitas aplicações, um modelo pode ser um simples conjunto de classes que contêm dados provenientes de um banco de dados e que têm pouco comportamento. Este tipo de modelo é conhecido como um modelo de objetos. Vejamos algumas das características das classes do modelo de objetos:

  • Validação de dados;
  • Propriedade de Junção - Muitas vezes você precisa do endereço do cliente completo em uma única sequência. Escrever o código que junte todas as propriedades relacionadas com o endereço em uma sequência cada vez que precisar, embora seja é viável, é repetitivo e propenso a erros. A classe Customer contém uma propriedade adicional, AddressInfo, que internamente se une as propriedades de endereço e os retorna como uma string, para que você não tenha que escrever o código para recuperar o endereço completo a cada vez que precisar.

Conectando as classes

As classes no modelo de objetos não estão isoladas, mas sim conectadas entre si. Por exemplo: a classe Order está conectada com a classe Customer e a classe Order_Detail está conectada com a classe Product.

No banco de dados, as tabelas são conectadas pelas colunas-chave estrangeiras. No modelo de objetos podemos referenciar diretamente outra classe usando a propriedade do tipo da classe referenciada. Por exemplo: a classe Order mantém uma referência a classe Customer usando a propriedade Customer (podemos usar o nome do cliente), cujo tipo é Customer.

Se um objeto precisa referenciar múltiplos objetos, você pode criar uma propriedade enumeration do tipo List<T>, onde T é o tipo de objeto na coleção. Por exemplo, um pedido precisa referenciar uma lista de detalhes (itens) e para fazer isso a classe Order contém a propriedade Order_Details, que é do tipo List<Order_Detail> (você não precisa, necessariamente, usar List<T>. Pode lançar mão de outras classes do tipo coleção, como Colletion<T>, HashSet<T> ou mesmo a classe não genérica ArrayList).

Quando você completar o processo de desenhar os relacionamentos do modelo de objetos, você deverá ter algo parecido com o que mostra a figura abaixo:

45118.gif

  1. A classe Order está ligada à classe Customer pela propriedade Customer;
  2. A Classe Order também contém detalhes através da propriedade Order_Details;
  3. Cada detalhe esta conectado ao produto através da propriedade Product.

O modelo de objetos atende uma grande parte dos cenários encontrados pelas aplicações mas existem casos em que você vai precisar de um maior nível de interação entre o modelo de objetos e o ambiente e, para isso, o modelo de objetos vai precisar conter comportamentos.

A evolução do modelo de objetos : o modelo de domínio

Um modelo de domínio é um modelo de objetos no qual as classes têm mais comportamentos. O comportamento que é adicionado ao modelo de classes de domínio cria uma integração ampla e rica entre as classes e o meio ambiente.

45119.gif

  • O modelo de domínio abrange o modelo de classes e repositórios;
  • O modelo de domínio usa a camada de infra-estrutura para abstrair a

    interação física com o banco de dados.

O modelo de domínio não envolve apenas as classes e seus dados, ele introduz um novo design para sua aplicação. As classes são integradas à camada de negócios e se comunicam com os módulos do repositório, que são um tipo de porta para o banco de dados. Assim, todas essas classes e módulos tornam-se uma única camada: o modelo de domínio.

O modelo de domínio não se comunica diretamente com o banco de dados. Uma camada de infra-estrutura que oculta a comunicação de dados e que está por baixo do modelo é que faz esse trabalho. Os repositórios lidam com a camada de infra-estrutura que são usadas para enviar os comandos, para recuperar ou atualizar os dados de um banco.

 

Nota: Como as classes estão cientes dos repositórios, eles podem recuperar dados do banco e assim oferecem uma nova gama de serviços para os desenvolvedores. O padrão de projeto modelo de domínio (Domain Model) contém muitas outras características. Para mais detalhes, consulte o livro de Eric Evans - Domain Driven Design.

Agora você já sabe como definir as camadas de um aplicativo para criar um design melhor e um código mais sustentável. Desenvolver em camadas é fundamental para uma aplicação bem-sucedida e toda essa discussão leva em conta que você tem que lidar com um banco de dados e com objetos cujos dados devem ser persistentes.

Agora, vamos descobrir como você pode fazer isso usando uma ferramenta ORM, como o Entity Framework.

 

Usando um ORM para construir a camada de acesso a dados

Uma ORM é uma framework que lhe permite construir aplicações baseadas em um paradigma que é completamente diferente do que você usa quando você trabalha diretamente com ADO.NET. Usando um ORM você pode apenas trabalhar com objetos e ignorar o banco de dados.

Um ORM permite mapear suas classes e propriedades em tabelas e colunas no banco. Você pode projetar suas classes e tabelas de forma independente e depois deixar o ORM usar as informações de mapeamento para gerar o código SQL para ler os dados a partir de um banco de dados, criar objetos com ela e persistir os dados nos objetos dentro do banco (o código SQL é executado através de ADO.NET, que permanece na camada mais baixa).

Dito desta forma, você pode pensar que um ORM é uma ferramenta que apenas gera código, mas ela faz muito mais do que isso. Um ORM gerencia as alterações feitas nos objetos e garante a integridade de um determinado objeto, suportando muitos ajustes de otimização. Além disso, um ORM lida com as diferenças entre os banco de dados relacionais e o paradigma OOP - que são diferentes em termos de granularidade dos dados.

 

Antes de dizer-lhe como usar um ORM, vamos examinar os problemas que ele resolve, de modo que você possa entender melhor como uma ferramenta ORM pode tornar a sua vida mais fácil.

1. A incompatibilidade da granularidade dos dados

 

O número de classes nem sempre vai ser igual ao número de tabelas no banco de dados, causando uma incompatibilidade conhecida como granularidade dos dados.

Geralmente o endereço residencial de um cliente consiste de rua, cidade, cep, país. Com frequência o endereço de entrega para pedidos possui a mesma informação. Quando você define a tabela no banco de dados, você cria colunas com essas informações nas tabela Customers e Orders.

Quando você define o modelo de classes você geralmente cria uma classe AddressInfo, que contém todas as propriedades relacionadas com o endereço e, então, você reutiliza esta classe nas classes Customer e Order. Ao final, você acaba tendo duas tabelas e três classes, conforme a figura abaixo:

45120.gif

As classes Order e Customer possuem a propriedade Adress do tipo AddressInfo, que contém a informação do endereço. No banco de dados, as colunas relacionadas com o endereço são repetidas nas tabelas Customers e Orders.

2. A incompatibilidade dos relacionamentos

Outra diferença entre os modelos relacionais e OOP está na forma como eles mantêm os relacionamentos. Pense sobre o relacionamento Order/Customer. Em um banco de dados, você cria uma coluna-chave estrangeira CustomerId na tabela Pedidos (tabela filho), que aponta para a coluna-chave primária CustomerId, da tabela Customers (tabela pai).

 

No modelo de objetos, você pode referenciar o cliente (Customer) a partir do pedido (Order), usando uma propriedade do tipo Customer (Cliente), por isso, não há necessidade de uma propriedade-chave estrangeira.

Em um banco de dados, as associações são direcionais da tabela filho para a tabela pai. No modelo de objetos, as associações podem ser tanto unidirecionais, como bidirecionais. Você pode ter a propriedade Customer na classe Order, mas também pode ter uma propriedade Orders na classe Customer.

45121.gif

Os Pedidos (Orders) estão relacionados aos seus Clientes (Customers) através de uma chave estrangeira no banco de dados. No modelo OOP utiliza-se um referência ao objeto.

No caso de um relacionamento muitos-para-muitos, as diferenças entre os bancos de dados relacionais e o paradigma OOP tende a crescer. Imagine o relacionamento entre as tabelas Employees e Territories no banco de dados Northwind. Eles não estão relacionados entre si, através de chaves estrangeiras, mas através de uma terceira tabela: EmployeeTerritories.

 

45123.gifNo modelo de objetos, você deixa as classes referirem-se diretamente entre si, sem recorrer a uma classe intermediária.

3. A incompatibilidade da herança

 

Suponha que você tenha que tratar em uma aplicação com dois tipos de clientes : pessoa física e jurídica. Você poderia criar uma classe base para todos os clientes e, a seguir, criar uma classe para cliente pessoa física e outra classe para pessoa jurídica e depois fazer com que essas duas classes herdem da classe base.

Nos banco de dados relacionais, o conceito de herança não existe. O que você pode fazer é criar um artefato para simular a herança. Você pode simular a herança no banco de dados utilizando um dos seguintes três métodos:

  • Table-Per-Hierarchy (TPH) - onde uma tabela contém os dados de todas as classes na hierarquia de herança e, geralmente, utiliza uma coluna discriminadora para determinar o tipo de objeto que está armazenado;
  • Table-Per-Type - (TPT) - onde cada classe na hierarquia de herança tem uma tabela e cada tabela adiciona apenas as colunas que são necessárias para o tipo;
  • Table-per-Concrete (TPC) - onde cada classe tem uma tabela, mas cada tabela contém todas as colunas mapeadas para todas as propriedades da classe mapeada.

Independentemente da abordagem que você escolher, você está adaptando o modelo relacional para representar algo para o qual ele não foi projetado.

4. A incompatibilidade dos tipos de dados

Existe também o problema do tipo de dados. Em um banco, você geralmente tem os tipos de dados varchar, int, datetime e outros tipos de dados que pode ou não ter uma contrapartida na plataforma .NET.

Como exemplo, veja o tipo de dados int do SQL Server. Você pode mapeá-lo para uma propriedade Int32 e ele vai funcionar perfeitamente. Agora, pense sobre o tipo de dados varchar, que pode ser facilmente mapeado para uma string. Mas se a coluna tem um comprimento máximo, você não pode representar o tipo varchar usando o tipo string da plataforma .NET sem ter que escrever um código para verificar o seu tamanho. A situação fica mais complicada para tipos de dados como TimeStamp, que são representados como um array de bytes.

Ao escrever o seu código usando ADO .NET, você tinha que tratar todas essas diferenças. Se você usar uma ferramenta ORM, ela trata essas diferenças para você e você pode se concentrar apenas nos objetos que interagem com o banco de dados.

Vimos, assim, os problemas que um ORM resolve e como isso pode tornar a sua vida mais fácil quando você lidar com aplicações com acesso a dados. Na segunda parte desse artigo veremos como usar a ferramenta ORM Entity Framework.

 

http://imasters.com.br/artigo/23696/dotnet/net-o-acesso-a-dados-usando-um-orm-entity-framework-parte-01

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.