EF Code First – Criando chaves que não sejam Identity

Dec 22
2011

Na construção de nossas aplicações há alguns casos em que queremos que uma coluna seja chave primária de uma determinada tabela, mas, queremos que esta informação não seja gerada pelo banco de dados, ou seja, queremos que esta informação seja fornecida pelo usuário ou seja obtida de outra forma (através de um cálculo ou através de uma consulta a um sistema externo).

Para exemplificar, vamos então analisar a classe abaixo:

public class Pessoa
{
    public int CPF { get; set; }
    public string Nome { get; set; }
    public string Sobrenome { get; set; }
    public int Idade { get; set; }
}

 
Como você pode ver esta classe é bem simples, ela contêm algumas informações de cadastro de uma pessoa. A nossa intenção principal aqui é que a informação de CPF seja fornecida pelo usuário que esteja efetuando o cadastro.
 
Vamos criar então outra classe chamada PessoaConfiguration, conforme abaixo:

class PessoaConfiguration : EntityTypeConfiguration<Pessoa>
{
    public PessoaConfiguration()
    {
        HasKey(p => p.CPF);
        Property(p => p.Nome).IsRequired();
        Property(p => p.Sobrenome).IsRequired();
    }
}

 
Obs: Se você quiser aprender mais sobre o código acima, sugiro a leitura do artigo:
Data Annotations x Fluent Api
 

Esta classe faz uso da Fluent API para configurar a classe Pessoa. Sendo assim, configuramos a propriedade CPF como chave primária da tabela e informamos que a propriedade Nome e Sobrenome serão obrigatórias.
 

Mas, o que há de errado com o código acima?

 
Vamos então tentar criar um registro no banco de dados. Veja o código abaixo:

static void Main(string[] args)
{
       var pessoa = new Pessoa
       {
           Nome = "Robson",
           Sobrenome = "Ramos"
       };

       using (var context = new Context())
       {
          context.Pessoas.Add(pessoa);
          context.SaveChanges();
       }
}

 
O código acima efetua a criação de um objeto Pessoa e efetua a inserção no banco de dados. Observe que não forneci a informação de CPF (que estava configurada como obrigatória). Veja como o registro foi criado na tabela:
 

 
Apesar da propriedade CPF ser configurada como obrigatória, o banco de dados gerou um id para ela. Isto aconteceu devido ao modo de funcionamento do Entity Framework: ao encontrar um campo inteiro configurado como chave primária ele então configurará a chave primária como Identity (auto-incrementável) no banco de dados.

Para resolvermos este problema, basta efetuar a seguinte configuração na classe PessoaConfiguration. Conforme abaixo:

 

class PessoaConfiguration : EntityTypeConfiguration<Pessoa>
{
    public PessoaConfiguration()
    {
        HasKey(p => p.CPF);
        Property(p => p.CPF).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        Property(p => p.Nome).IsRequired();
        Property(p => p.Sobrenome).IsRequired();
    }
}

 
Observe sexta linha do código acima, esta instrução diz que a coluna CPF não terá seu valor gerado pelo banco de dados, ou seja, estamos sobrescrevendo a convenção do Entity Framework para que o valor seja informado no momento da inserção do registro.

Agora, precisamos alterar o código que instancia o objeto pessoa informando um número de CPF. Veja abaixo:

static void Main(string[] args)
{
            var pessoa = new Pessoa
            {
                CPF = 12345678,
                Nome = "Robson",
                Sobrenome = "Ramos"
            };

            using (var context = new Context())
            {
                context.Pessoas.Add(pessoa);
                context.SaveChanges();
            }
}

 
Agora, se olharmos na tabela podemos verificar que a informação agora foi salva com sucesso:
 

EF Code First – Data Annotations x Fluent API

Dec 22
2011

Ao se trabalhar com o Entity Framework usando o modo Code First há a possibilidade de se trabalhar de duas formas com as configurações do nosso Model : Data Annotations e Fluent API. Neste artigo mostarei como cada configuração sem comporta e tentarei estabelecer os prós e contras de cada uma.

Para iniciarmos crie um projeto do tipo Console Application (dê o nome que você acha mais conveniente) e usando o Nuget procure o pacote do Entity Framework e clique em Install. Conforme abaixo:

NuGet

Após isso, crie uma classe chamada Carro e adicione algumas propriedades igual ao código abaixo:

class Carro
{
    public int CarroId             { get; set; }
    public string Fabricante       { get; set; }
    public string Modelo           { get; set; }
    public string Placa            { get; set; }
}

Data Annotations

Data Annotations são atributos que aplicamos diretamente ao nosso Model com a finalidade de efetuarmos validações, definir formatos de campos, ajudar o Entity Framework no processo de geração do banco de dados, dentre outras coisas…

Vamos então alterar a nossa classe criada anteriormente.


[Table("Automoveis")]
class Carro
{
[Key]
public int CarroId { get; set; }

[Required]
public string Fabricante { get; set; }

[Required]
public string Modelo { get; set; }

[MaxLength(8)]
public string Placa { get; set; }
}

Obs: Para o código acima é necessário referenciar o assembly System.ComponentModel.DataAnnotations

O código acima efetuou as seguintes configurações:

• Esta classe será mapeada para a tabela Automóveis
• A propriedade CarroId é chave primária
• A propriedade Fabricante é obrigatória
• A propriedade Modelo também é obrigatória
• A propriedade Placa deve ter no máximo dígitos

Fluent API

O conceito de Fluent API não vêm do Code First, mas, a sua idéia principal é usar chamada de métodos para produzir código fácil de ler e entender aos olhos do desenvolvedor. Com a ajuda do IntelliSense e fazendo uso de expressões lambda podemos configurar as nossas classes usando uma classe separada só para cuidar disso.

Antes de fazermos as alterações, remova os atributos adicionados no passo anterior. Embora seja possível trabalhar das duas maneiras é recomendável usar apenas umas das duas formas.

Depois disso, crie mais uma classe chamada CarroConfiguration e adicione o código abaixo:

class CarroConfiguration : EntityTypeConfiguration<Carro>
{
    public CarroConfiguration()
    {
        ToTable("Automoveis");
        HasKey(c => c.CarroId);
        Property(c => c.Fabricante).IsRequired();
        Property(c => c.Modelo).IsRequired();
        Property(c => c.Placa).HasMaxLength(8);
    }
}

Pronto, é só isso!

As configurações acima tratam-se das mesmas configurações realizadas utilizando o Data Annotation.

Mas, para que o Entity Framework possa reconhecer a nossa classe como “configuradora” da classe Carro precisamos registrá-la no processo de criação do Model, mas, isso é assunto para outro post. =)

Conclusão

Embora os dois métodos são bem simples eu, particularmente, gosto bastante de trabalhar com a Fluent API. Isto porque a adição de inúmeros atributos no nosso Model poluirá visualmente a nossa classe e tornará a leitura complicada. Além disso, com a Fluent API temos uma separação clara de responsabilidade entre o Model em si a sua configuração.
Um outro ponto a se levar em consideração é que há algumas configurações que só podem ser alcançadas com a Fluent API, pois, o uso de atributos possui algumas limitações a serem levadas em consideração.

Visit Our Friends!

A few highly recommended friends...

Pages List

General info about this blog...