PantaNet

Introdução ao ADO.NET Entity Framework 4.1 - parte 3: Mapeamentos complexos

No primeiro post dessa minha série sobre EF 4.1, mostrei um exemplo com três classes POCO, a criação de um Contexto herdado de DbContext para acesso ao banco e um Database Initializer para permitir alguma lógica de inicialização do banco de dados.

 

No segundos post o mapeamento foi refinado com alguns atributos sobre as classes e suas propriedades, e foram criados alguns formulários para demonstrar operações CRUD, efetuando inserções, edições, e exclusões, utilizando puramente orientação a objeto, sem a necessidade de executar uma única instrução SQL.

 

Para esse terceiro post, preparei algumas classes adicionais com exemplos de mapeamentos mais complexos e no final vou mostrar um formulário mestre-detalhe.

 

Voltando ao banco de dados, temos agora a seguinte estrutura:

 

 

As três primeiras tabelas já eram conhecidas: Cidades, Estados, Paises.

Foi adicionada uma tabela Pessoa, que faz um relacionamento Um-Para-Um com as tabelas: PessoasJuridicas e PessoasFisicas. Cada pessoa pode ter um ou mais endereços, e para isso foi criada a tabela Enderecos. Cada endereço se relaciona com uma cidade, e possui um tipo de endereço, e então temos a tabela TiposEndereco.

 

Relacionamento One-To-One (Um-Para-Um)

Para que o EF entenda esse tipo de relacionamento, é necessário que haja em ambos os lados uma propriedade complexa com a palavra reservada virtual. A classe Pessoa ficou assim:

 

 

A classe PessoaJuridica contém uma chave própria porém sem o atributo Identity (o valor do Id virá da tabela Pessoa), ou seja, o campo Id é chave primária mas também é chave estrangeira, referenciando o campo Id da tabela Pessoa. Repare na propriedade complexa referenciado a classe Pessoa e no atributo ForeignKey:

 

A mesma situação ocorre com a classe PessoaFisica, porém nesse caso aproveitei para mostrar como usar a API Fluente do EF, pois em algumas situações não existe todos os atributos necessários, então introduzi uma classe interna para configurar o campo "Sexo" pois quero que no banco de dados o tipo seja char(1) e não varchar(1).

 

O método Property possui um parâmetro para usar com expressão lambda. Para que essa classe seja utilizada pelo EF, temos que referenciá-la no Contexto, caso contrário, será ignorada. Para fazer isso, devemos sobreescrever o método OnModelCreating e adicionar uma nova instância dessa classe, da seguinte forma:

 

Nas outras classes adicionadas, não há novidades em relação ao EF, tudo já foi demonstrado neste post e em posts anteriores.

 

Vou destacar a alteração que fiz na classe MyInitializer, onde cadastrei uma pessoa, uma pessoa física, jurídica, um endereço e um tipo de endereço.

 

 

Formulário Mestre-Detalhe (Master-Detail)

Neste formulário, vou apresentar uma listagem com as pessoas que foram cadastradas e seus respectivos endereços:

 

Para recuperar a lista de pessoas, criei uma lista que contém os dados da pessoa (Id, Nome, Status) da tabela pessoa e na mesma lista adicionei um campo para o Cpf no caso de a pessoa ser pessoa física e o Cnpj no caso de a pessoa ser jurídica. Pela maneira que modelei esse banco de dados, a mesma pessoa pode ser tanto física quanto jurídica. Normalmente eu faria um classe específica chamada PessoaEnderecoModel, somente para exibir essas informações, mas desta vez fiz diferente, criei um tipo anônimo, converti para um List<T> e preenchi os dados ao percorrer os resultados da consulta. Ficou da seguinte forma:

 

 

E finalmente, para exibir os endereços da pessoa que foi selecionada na lista, eu pego o Id da pessoa que foi selecionada através do valor da célula do GridViewMaster, e faço uma consulta filtrando os endereços usando a cláusula Where. Deixei comentada as duas formas de utilizar o EF com LINQ. Use a forma de sua preferência, o resultado será o mesmo!

 

Próximo artigo vou falar um pouco sobre validação, em seguida mostrarei uma classe base para ser usada no padrão repositório e falarei mais sobre o DbContext e utilizar o padrão UnitOfWork. Tem assunto ainda pra mais uns dez posts!

 

[]'s

Exibições: 2209

Comentário de Jone em 21 abril 2011 às 19:53

Link para baixar o projeto atualizado para este post:

 

PostPantanetEf41_parte3.rar

Comentário de Hugo Campos em 4 julho 2011 às 9:56

Bom dia Jone,

 

Será que você poderia me dar uma ajuda nisso.

 

var EnderecoComercial = new TipoEndereco { Descricao = "Comercial" };
                var EnderecoResidencial = new TipoEndereco { Descricao = "Residencial" };

                ctx.TiposEndereco.Add(EnderecoComercial);
                ctx.TiposEndereco.Add(EnderecoResidencial);

teria alguma outra forma de fazer isso?

Comentário de Jone em 4 julho 2011 às 12:47

Dessa forma que vocë fez está correta, mas tem ainda uma maneira mais direta ainda:

 

ctx.TiposEndereco.Add(new TipoEndereco { Descricao = "Comercial"});

ctx.TiposEndereco.Add(new TipoEndereco { Descricao = "Residencial"});

ctx.SaveChanges();

Comentário de Thiago Lagos em 21 dezembro 2011 às 6:00

Primeiramente gostaria de parabenizar pelo excelente trabalho!

Gostaria de saber se poderia nos mostrar como ficaria esta estrutura com MySql ao invés de SQLExpress.

Comentário de Reuber Junior em 8 maio 2012 às 20:36

Olá Jone, muito obrigado por compartilhar estes post´s

Tenho uma estrutura parecida com o cadastro de pessoas ( pessoas - pessoas juridicas - pessoas fisicas).

Como faço para que quando eu excluir uma pessoa, a exclusão se propague para as tabelas filhas? Exclusão em cascata? Com uma estrutura parecida, quando o Entity Framework cria o banco, ele não "adiciona" a opção de deleção em cascata nas tabelas filhas. Poderia me ajudar?

Comentar

Você precisa ser um membro de PantaNet para adicionar comentários!

Entrar em PantaNet

Fotos

Carregando...
  • Adicionar fotos
  • Exibir todos

Apoio





 

© 2012   Criado por Gustavo Malheiros.

Badges  |  Relatar um incidente  |  Termos de serviço