Entity Framework – Data Annotations

O Entity Framework (EF) permite que utilizemos nossas classes para construção e mapeamento de nosso banco de dados, para tanto algumas convenções são necessárias para que ocorra o mapeamento. Mas muitas vezes as convenções não são suficientes, pois em determinados cenários a representação de nossas classes não é a mesma representação de nosso banco de dados. Este post objetiva apresentar o uso de DataAnnotations (atributos de mapeamento) presentes no namespace  System.ComponentModel.DataAnnotations para construção de nossas classes. Abaixo seguem alguns dos atributos mais utilizados, seu modo de uso e seu impacto no banco de dados.

Key
As entidades mapeadas pelo Entity Framework precisam de uma propriedade que trabalhe como chave primária (propriedade chave), que trabalhe como “propriedade de rastreamento” do dado dentro da tabela, contendo um valor que diferencie o registro dos demais ali armazenados.  Por convenção, o EF procura em sua classe por uma propriedade nomeada como “Id” ou uma propriedade nomeada com o nome da classe concatenada a palavra “Id” (i.e. ProdutoId, PedidoId, ClienteId). Caso o EF não encontre uma propriedade que esteja dentro de suas convenções, então uma exception será disparada exigindo que a classe possua uma propriedade chave. Caso sua classe não possua uma propriedade cujo nome esteja dentro destas convenções então é possível utilizar o atributo Key para indicar qual propriedade de sua classe deverá funcionar como propriedade chave.

Impacto no banco de dados: será gerada uma primary key com identação automática (identity).

figuraAtributoKey

Required
O atributo Required indica que um atributo em particular é obrigatório e que não poderá deixar de ser valorizado.

Impacto no banco de dados: o uso deste atributo adiciona uma restrição “not null” na coluna gerada no banco de dados.

figuraDataAnnotationRequired

MaxLength e MinLength
Estes atributos validam o tamanho do dado inserido, limitando o tamanho máximo e/ou indicando seu tamanho mínimo.

Impacto no banco de dados: o tamanho das colunas criadas no banco de dados serão limitados pelo uso do atributo MaxLenght. O tamanho default das colunas, sem o uso do atributo MaxLenght, é de 128 caracteres.

figuraMaxLengthMinLength

NotMapped
Existem cenários onde nem todos os atributos de nossas classes devem ser mapeados para o banco de dados. Este cenário existe quando alguma das propriedades de nossa classe é resultante de alguma ação dinâmica ou cálculo, e que não precisa ser armazenada na base de dados.

Impacto no banco de dados: nenhum, esse atributo não acarreta na criação de nenhuma coluna, na verdade ele é ideal para que a coluna não seja criada.

figuraNotMapped

ComplexType
Não é incomum que nossa classes possuam propriedade que sejam instâncias de outros objetos, cujos dados não queremos armazenar em tabelas dedicadas. No nosso exemplo podemos incluir uma propriedade que indique qual o endereço de entrega de um malote, mas talvez não seja necessário possuir uma tabela exclusiva para o armazenamento dos endereços, podemos desejar que nossa tabela de malote possuísse as colunas de endereço dentre suas colunas. Para tanto, devemos utilizar o atributo ComplexType para indicar este cenário. Detalhe, este atributo deve ser incluído na classe que corresponde ao tipo complexo, não na classe que contém o atributo com o tipo complexo.

Impacto no banco de dados: nenhuma nova tabela será criada, em contraponto, as propriedades existentes na classe que  contém o atributo ComplexType serão mapeadas para a tabela que contém a propriedade que utiliza o tipo de dados.

figuraComplexType01

figuraComplexType02

Table and Column
Podem existir dois casos onde os nomes das colunas das tabelas não são os mesmos dos nomes dos atributos das classes,  sendo: o primeiro, quando o banco de dados já existe e é preciso criar o mapeamento para o mesmo; segundo, quando por alguma necessidade do cliente o banco de dados deve possuir uma nomenclatura de acordo com um conjunto de regras e padrões.

O atributo Table permite o mapeamento de uma classe para uma tabela, substituindo as conversões do Entity Framework.

figuraAtributoTable

O atributo Column permite a definição do nome da coluna que será mapeada pelo Entity Framework. No exemplo abaixo é  possível notar que também é possível a combinação de diferentes atributos de mapeamento em uma única propriedade.

figuraAtributoColumn

ForeignKey
O atributo ForeignKey indica qual propriedade na classe representa o campo que corresponde à chave estrangeira entre as tabelas. Note que no exemplo abaixo o atributo ForeignKey está acima da propriedade que representa a navegação entre as duas entidades.

figuraForeignKey

Por
Fernando Henrique Inocêncio Borba Ferreira.

Publicidade

Linq to SQL – Atributos de Mapeamento Objeto-Relacional

Quando trabalhamos com LINQ to SQL nosso mapeamento objeto-relacional pode ser construído de duas maneiras: através de um arquivo externo (XML Mapping Source) ou através do mapeamento das classes da aplicação (Attribute Mapping Source). Na grande maioria dos casos acabamos por realizar o mapeamento dos atributos das classes da aplicação e utilizamos o Object Relational Designer – assistente do Microsoft Visual Studio que gera o mapeamento do banco de dados automaticamente para nossa aplicação.

O mapeamento ocorre da seguinte maneira:
– O banco de dados é mapeado para uma instância de um DataContext.
– Uma tabela é mapeada para uma classe
– As colunas da tabela são mapeadas para as propriedades das classes

Podemos construir esse mapeamento manualmente, sem utilizar o assistente do Microsoft Visual Studio, a fim de tornar o código mais simples, gerenciável e inteligível. Para tanto devemos fazer uso dos atributos de mapeamento do LINQ, tais atributos estão contidos no namespace System.Data.Linq.Mapping. Para ter acesso a esses atributos precisamos fazer referência a dll System.Data.Linq.

O mapeamento de uma tabela vai se parecer com o código a seguir:

Mapclasses

… baseado na estrutura da seguinte tabela:

clip_image003

Comparando o código C# e o código SQL, podemos considerar alguns pontos:
– O atributo Table, localizado acima da definição da classe Customer, indica que esta classe corresponde ao mapeamento de uma tabela, mais especificamente a tabela tbMappingCustomer, especificada pelo valor definido na propriedade Name .

– O atributo Column indica que uma propriedade corresponde a uma coluna da tabela, isto é, o atributo Column simboliza o mapeamento entre uma coluna da tabela e uma propriedade da classe.

– O atributo Column possui diversas propriedades Name e CanBeNull são apenas algumas, mas são algumas das principais. Em um próximo post discutiremos outras possibilidades. A propriedade Name do atributo Column indica qual coluna da tabela deverá ser mapeada pelo LINQ to SQL, e a propriedade CanBeNull indica quais colunas aceitam valores nulos na base de dados.

– As propriedades IsDbGenerated e IsPrimaryKey são propriedades do atributo Column, que são utilizadas apenas na propriedade ID, pois essa propriedade mapeia a chave primária da tabela. A propriedade IsDbGenerated indica que o atributo possui valores gerados pelo próprio banco de dados, no nosso caso os valores dessa coluna da tabela são gerados automaticamente pelo Identity(1, 1) citado no código SQL. A propriedade IsPrimaryKey é autoexplicativa, ela indica se a propriedade corresponde ao mapeamento da chave primaria da tabela.

Para persistir as informações é preciso utilizar um objeto que faça a ponte entre a aplicação e o banco de dados, este objetivo é o DataContext. A função do DataContext é traduzir o mapeamento objeto-relacional para comandos que possam ser interpretados pelo banco de dados, assim como converter os dados retornados pelo banco de dados para as entidades do mapeamento objeto-relacional.

No caso, costumo criar uma classe que herde de um DataContext, e que para cada tabela, crie-se um atributo do tipo Table<E> que referencie uma entidade mapeada para a aplicação. Na imagem abaixo demonstro como faço essa implementação.

DataContext

Abaixo um exemplo de como unir a utilização do DataContext customizado, com as entidades mapeadas manualmente.

Implementacao

Obrigado.
[]s!

Referências indicadas:
http://oreilly.com/catalog/9780596519254
http://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.aspx
http://blogs.microsoft.co.il/blogs/bursteg/archive/2007/09/23/24907.aspx
http://msdn.microsoft.com/en-us/library/bb386971.aspx