Chave estrangeira e Associação Independente no Entity Framework
Neste artigo é apresentada a utilização do uso das associações por Foreign Key (Chave Estrangeira) e Independent Associations (Associação independente), demonstrado através de exemplo prático.
Baixe a versão do código demonstrado neste artigo no CodePlex http://efkey.codeplex.com
Baixe a versão do código demonstrado neste artigo no GitHub https://github.com/cleytonferrari/efkey
Nas primeiras versões do Entity Framework só era possível fazer um único tipo de associação entre as entidades, a Independet Associations, esta primeira abordagem de relacionamento entre as entidades era totalmente orientada a objeto, onde a relação entre dois ou mais objetos é feita através de referencias. Por exemplo, um objeto Produto que possui dentro dele (associação) outro objeto Categoria.
public class Produto { public int Id { get; set; } public string Descricao { get; set; } public Categoria Categoria { get; set; } }
O problema deste tipo de associação é que o Entity Framework torna, por vezes, muito complexa a sua implementação, seguindo o raciocínio do exemplo do Produto acima, para adicionar um novo produto, é preciso fazer uma busca nas categorias, achar um objeto categoria e associar ele (com todas as suas dependências/propriedades, no caso a propriedade UnidadeDeMedida) a este produto. E esta complexidade tende a aumentar em objetos muito complexos, que possuam vários outros objetos dentro.
class Program { static void Main() { var meucontexto = new MeuContexto(); var produto = new Produto(); produto.Descricao = "Arroz"; produto.Categoria = meucontexto.Categorias.Include("UnidadeDeMedida").ToList().FirstOrDefault(); meucontexto.Produtos.Add(produto); meucontexto.SaveChanges(); } }
Observe, que foi solicitado ao Entity Framework para incluir na sua busca, a UnidadeDeMedida, que é uma associação que existe entre as Classes Categoria e UnidadeDeMedida, como é demonstrado abaixo.
public class Categoria { public int Id { get; set; } public string Nome { get; set; } public UnidadeDeMedida UnidadeDeMedida { get; set; } } public class UnidadeDeMedida { public int Id { get; set; } public string Descricao { get; set; } public string Abreviacao { get; set; } }
Logo, se tenho uma classe que possui varias associações, é necessário trazer todas estas associações “secundárias” para realizar uma simples associação entre Produto e Categoria.
Já no Entity Framework 4 ou superior, o time de desenvolvimento do Entity Framework incluiu um novo tipo de associação onde o modelo conceitual inclui a propriedade do tipo Foreign Key, para definir as associações entre as entidades. Voltando ao nosso exemplo do Produto, agora ao invés de somente ter uma propriedade do tipo Categoria, o objeto Produto teria outra propriedade do tipo int, por convenção, o nome da propriedade Foreign Key é o nome da Propriedade Complexa associada, seguida pelo sufixo Id (no caso CategoriaId), que seria usada como Foreign Key (chave estrangeira), e nesta abordagem, na hora de cadastrar um novo produto, bastaria passar o Id da Categoria, para essa propriedade do tipo int, e a associação estaria feita, o Entity Framework se encarregaria do resto.
class Program { static void Main() { var meucontexto = new MeuContexto(); var produto = new Produto(); produto.Descricao = "Arroz"; produto.CategoriaId = meucontexto.Categorias.ToList().FirstOrDefault().Id; meucontexto.Produtos.Add(produto); meucontexto.SaveChanges(); } } public class Produto { public int Id { get; set; } public string Descricao { get; set; } public int CategoriaId { get; set; } public Categoria Categoria { get; set; } }
Repare que neste exemplo, não é mais necessário a inclusão da UnidadeDeMedida, que esta associada a categoria, para que se possa criar uma associação entre Produto e Categoria.
Este artigo não tem o propósito de debater os meandros desta abordagem se ela é boa ou não, se quebra ou não as regras da orientação objeto, uma vez que se tem a Foreign Key para fazer associação entre objetos, o próprio time de desenvolvedores do Entity Framework escreveu um artigo sobre isso, que diz que essa decisão deve ser tomada pelo desenvolvedor.
Verdade seja dita, o uso de Foreign Key diminui bastante a complexidade do código, o que torna muito mais fácil a manutenção futura, uma vez que não é preciso trazer todo o emaranhado de objetos complexo associadas a uma entidade, para fazer uma simples associação entre esses objetos, sem levar em conta o desempenho nas consultas realizadas para essas associações.
Exemplo completo, para referencia:
using System; using System.Data.Entity; using System.Linq; namespace ChaveEstrangeira { class Program { static void Main() { var meucontexto = new MeuContexto(); var categoria = new Categoria(); categoria.Nome = "Alimentos"; categoria.UnidadeDeMedida = new UnidadeDeMedida { Abreviacao = "PCT", Descricao = "Pacote" }; meucontexto.Categorias.Add(categoria); meucontexto.SaveChanges(); var produto = new Produto(); produto.Descricao = "Arroz"; produto.CategoriaId = meucontexto.Categorias.ToList().FirstOrDefault().Id; //produto.CategoriaId = 1; //Caso saiba o id, basta passar somente o Id. meucontexto.Produtos.Add(produto); meucontexto.SaveChanges(); //Busca no contexto o produto cadastrado var produtoRetornado = meucontexto.Produtos.Include("Categoria").ToList().FirstOrDefault(); Console.WriteLine(produtoRetornado.Categoria.Nome); } } public class Produto { public int Id { get; set; } public string Descricao { get; set; } public int CategoriaId { get; set; } public Categoria Categoria { get; set; } } public class Categoria { public int Id { get; set; } public string Nome { get; set; } public int UnidadeDeMedidaId { get; set; } public UnidadeDeMedida UnidadeDeMedida { get; set; } } public class UnidadeDeMedida { public int Id { get; set; } public string Descricao { get; set; } public string Abreviacao { get; set; } } public class MeuContexto : DbContext { public DbSet<Produto>; Produtos { get; set; } public DbSet<Categoria> Categorias { get; set; } } }
Para Saber mais