Entity Framework - Definindo um modelo com herança Table Per Type
Este série de artigos é dedicada ao Entity Framework e tem o objetivo de dar uma introdução básica e uma visão geral de como usar este importante recurso da plataforma .NET. Os artigos são parcialmente baseados na documentação da MSDN de onde são citadas as respectivas referências.
Iniciando com o Entity Framework
Conceito
A ADO .NET Entity Framework foi projetado para permitir que a criação de aplicações com acesso a dados use o modelo de programação feito contra um modelo conceitual ao invés do antigo modelo de programação feito diretamente contra um banco de dados relacional. O objetivo é diminuir a quantidade de código e o tempo de manutenção necessária exigida nestas aplicações orientada a dados.
A ADO .NET Entity Framework é uma framework que abstrai o esquema de um banco de dados relacional e o apresenta como um modelo conceitual. Abaixo a figura que representa a arquitetura em camadas do Entity Framework: (Até o lançamento do VS 2010, previsto para o primeiro trimestre.)
Data Source
: Representa a base da arquitetura onde estão armazenados os dados;
Data Providers : Os dados são acessados por um ADO.NET data provider. Até o momento tanto o SQL Server como o MySQL são suportados e provavelmente em breve os principais RDBMS do mercado (Oracle, MySQL, DB2, Firebird, Sybase, VistaDB, SQLite, ...) terão um provider para o EF. Entity Data Model (EDM) : O Entity Data Model é constituído de 3 partes:
Entity Client : O EntityClient é um provedor gerenciado ADO.NET que suporta o acesso a dados descritos no EDM. Ele é similar ao SQLClient, e fornece diversos componentes como EntityCommand, EntityConnection e EntityTransaction; Object Services : Este componente permite realizar consultas, atualizações, inclusões e exclusões nos dados, expressados como objetos CLR fortemente tipados que são instâncias de entity types. Ele da suporte tanto a consultas Entity SQL como LINQ to Entities; Entity SQL (ESQL) : É uma derivação da Transact-SQL, projetada para consultar e manipular entidades definidas no EDM. Ele dá suporte herança e associação sendo que tanto os componentes Object Services como os componentes Entity Client podem executar instruções Entity SQL; LINQ to Entities : É
uma linguagem de consulta fortemente tipada para consultar entidades
definidas no EDM; |
Criar, modificar e deletar objetos e aplicar estas alterações ao banco de dados é muito fácil com o Entity Framework. Através do Object Services que gerencia todas as alterações feitas nos objetos e gera e executa as instruções T-SQL que irão realizar as operações de inclusão, alteração e exclusão contra a fonte de dados. Tudo isso é feito através da chamada do método SaveChanges do ObjectContext (equivalente ao SubmitChanges do LINQ to SQL).
Quando usamos uma ferramenta OR/M como o Entity Framework desejamos definir da melhor forma possível o nosso modelo de entidades de forma a que tenhamos um bom desempenho e que o esforço necessário para tratar o modelo seja o mínimo possível. Como todos já sabem o modelo relacional de banco de dados não se ajusta adequadamente ao paradigma da orientação a objetos e uma ferramenta OR/M que se preze deve oferecer recursos para tornar a discrepância entre esses dois mundos o menos traumática possível.
Na programação orientada a objetos quando um objeto é um tipo de outro objeto podemos usar a herança para compartilhar suas propriedades de forma que as propriedades da classe base são expostas diretamente para o tipo derivado.
A herança é um recurso da orientação objeto que não existe nativamente no mundo relacional e uma ferramenta OR/M deve oferecer recursos para que possamos implementar a herança em nosso modelo de entidades de forma a obter um melhor rendimento. Felizmente o Entity Framework oferece esses recursos.
Nota: No paradigma da orientação a objetos a herança é muitas vezes usada para representar que apresentam uma relacionamento do tipo É-um. Ou seja quando um objeto é uma especificação do outro objeto.
O Entity Framework suporta 3 modelos diferentes de herança:
O modelo Table-per-Type é uma forma de modelar a herança onde cada entidade é mapeada para uma tabela diferente na camada de armazenamento. Cada tabela contém todas as propriedades para a entidade bem como uma chave que mapeia em última instância a tabela raiz/entidade.
A herança do tipo Table per Type (TPT) define uma herança que é descrita no banco de dados com tabelas separadas onde uma tabela fornece detalhes adicionais que descrevem um novo tipo baseado em outra tabela. Este cenário é mais comum do que se imagina e pode ser visto na figura abaixo que exibe duas tabelas onde podemos aplicar a herança TPT.
Vejamos um modelo bem simples
onde podemos usar a herança TPT: A figura ao lado mostra o relacionamento entre a tabela Contato e Clientes. Onde um contato pode ter uma entidade cliente relacionada.
|
Vamos mostrar um exemplo prático definindo um modelo conceitual do tipo Table Per Type (TPT) para isso eu vou criar um modelo de dados bem simples usando o Microsoft SQL Server 2008 Express e o SQL Server 2008 Management Studio Express Edition.
Abaixo temos as tabelas : Pessoa, Supervisor, Professor , Aluno e Estagiário.
Nosso objetivo é implementar o modelo conceitual da herança Table Per Type suportada no EDM de forma que possamos ter acesso as informações compartilhadas entre as tabelas. |
Eu não vou entrar no mérito do modelo de dados pois ele esta sendo usado apenas para ilustrar a implementação da herança TPT no Entity Framework.
Nota: Pegue o script para gerar as tabelas aqui : Escola.sql
Neste caso estamos modelando uma hierarquia de herança onde temos a entidade base Pessoa e 3 entidades que herdam de Pessoa :: Aluno, Supervisor e Professor. Além disso temos a entidade Estagiario que herda da entidade Aluno.
Implementando o modelo da herança Table Per Type no Entity Framework
Vamos usar o Visual Studio 2008 e criar um projeto do tipo Windows Forms Application com o nome EF_herancaTPT;
A seguir no menu Project selecione Add New Item e escolha o template ADO .NET Entity Data Model, informe o nome Escola.edmx e clique Add;
A seguir selecione a opção Generate From dataBase e clique no botão Next>;
A seguir selecione a conexão com o banco de dados Escola e clique em OK;
A seguir aceite os valores padrões informados para a connection String e clique no botão Next>;
Na janela seguinte selecione as tabelas criadas , aceite o nome padrão para o namespace e clique em Finish;
Como resultado final será exibida o modelo de entidades criados no descritor do Entity Framework. O nosso EDM:
Pois é agora que o nosso trabalho vai começar.
Vamos começar alterando os nomes das entidades alterando o nome da propriedade Entity Set Name para o plural em todas as entidades. Veja abaixo a janela de propriedades para a entidade Pessoa:
Da mesma forma altere a
propriedade Entrity Set Name das demais entidades para:
|
A seguir vamos excluir todas as associações geradas no EDM selecionando cada uma delas e pressionando a tecla Delete. Na figura abaixo vemos as associações selecionadas e em seguida excluídas:
A seguir selecione a entidade Pessoa e clique com o botão direito do mouse selecionando Add -> Inheritance;
Será apresentada a janela Add Inheritance onde iremos selecionar a entidade base - Pessoa e a derivada Aluno clicando em OK;
Repita o procedimento acima incluindo a herança para as entidades derivadas Professor e Supervisor;
Finalmente selecione a entidade Aluno e clique com o botão direito e selecione Add -> Inheritance e na janela Add Inheritance selecione a entidade base Aluno e a entidade derivada Estagiario;
A final deveremos ter o seguinte modelo no descritor do EF:
A seguir vamos excluir as propriedades AlunoID, estagiarioID, supervisorID e professorID das entidades pois será herdada a propriedade pessoaID;
Para excluir essas propriedades selecione-as, clique com o botão direito do mouse, e selecione a opção Delete;
Como excluímos essas propriedades das entidades derivadas, a coluna pessoaID da tabela correspondente não esta mais mapeada. Precisamos então refazer o mapeamento para que a propriedade pessoaID seja herdada. Vamos lá...
Selecione cada uma das entidades derivadas e na janela Mapping Details mapeie cada coluna para a coluna pessoaID conforme a figura abaixo mostra para a entidade Supervisor:
Faça este processo para cada entidade derivada incluindo entidade Estagiario.
Pronto. Com isso terminamos de criar o nosso modelo conceitual baseado na herança TPT.
Vamos testar...
Vamos definir no formulário form1.vb, criado por padrão, uma interface bem simples apenas para mostrar que temos acesso as propriedades herdadas pelas entidades derivadas da entidade base.
Nota: Eu poderia ter criado uma aplicação console, seria mais simples ainda mas preferi criar uma aplicação Windows Aplication.
No formulário form1.vb inclua os seguintes controles : 5 Labels, 5 ListBox e 5 Button conforme o leiaute da figura abaixo:
Vamos iniciar exibindo a entidade Pessoa e para isso vamos incluir o código abaixo no evento Click do botão Exibir Pessoas:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Using escola As New EscolaEntities1 Dim pessoa = From p In escola.Pessoa _ Select p For Each p As Pessoa In pessoa lstPessoa.Items.Add(p.nome & "-" & p.email) Next End Using End Sub |
Neste código definimos a variável escola como uma instância do nosso Contexto (ObjectContext) e em seguida efetuamos uma consulta retornando os objetos da entidade Pessoa.
Para exibir as propriedades da entidade percorremos a entidade usando um laço For/Each.
Vamos agora exibir a entidade Professor. Para acessar as propriedades herdadas das entidades derivadas incluímos o código a seguir no evento Click do botão : Exibir Professores:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Using escola As New EscolaEntities1 Dim pessoa = From p In escola.Pessoa.OfType(Of Professor)() _ Select p For Each p In pessoa lstProfessor.Items.Add(p.nome & "-" & p.email & "=>" & p.salario) Next End Using End Sub
|
Neste código usamos o recurso da herança criada no modelo Table Per Type onde selecionamos as propriedades do tipo derivado Professor:
Dim pessoa = From p In
escola.Pessoa.OfType(Of
Professor)() _
Select p
Observe que após feito este procedimento temos acesso as propriedades herdadas : nome e email e da propriedade salario da entidade Professor.
For Each p In pessoa
lstProfessor.Items.Add(p.nome & "-" & p.email & "=>" & p.salario)
Next
Para exibir as propriedades para as demais entidades o procedimento é o mesmo mudando apenas o nome do tipo e da propriedade que desejamos acessar. Veja abaixo o código referente aos demais botões (todos no evento Click):
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click Using escola As New EscolaEntities1 Dim pessoa = From p In escola.Pessoa.OfType(Of Supervisor)() _ Select p For Each p In pessoa lstSupervisor.Items.Add(p.nome & "-" & p.email & "=>" & p.turno) Next End Using End Sub
|
Entidade Supervisor |
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click Using escola As New EscolaEntities1 Dim pessoa = From p In escola.Pessoa.OfType(Of Aluno)() _ Select p For Each p In pessoa lstAluno.Items.Add(p.nome & "-" & p.email & "=>" & p.nota & "," & p.curso) Next End Using End Sub
|
Entidade Aluno |
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click Using escola As New EscolaEntities1 Dim pessoa = From p In escola.Pessoa.OfType(Of Estagiario)() _ Select p For Each p In pessoa lstEstagiario.Items.Add(p.nome & "-" & p.email & "=>" & p.curso & "," & p.creditos) Next End Using End Sub
|
Entidade Estagiario |
O resultado obtido pode ser visto na figura abaixo :
Uma outra forma de obter o mesmo resultado seria usar o código exibido a seguir que coloquei no evento Click do botão - Exibir Todos :
Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click Using escola As New EscolaEntities1 Dim pessoa = From p In escola.Pessoa _ Select p For Each p As Pessoa In pessoa lstPessoa.Items.Add(p.nome & "-" & p.email) Next For Each tp In pessoa If TypeOf tp Is Professor Then Dim p As Professor = DirectCast(tp, Professor) lstProfessor.Items.Add(tp.nome & "-" & tp.email & "=>" & p.salario) End If If TypeOf tp Is Supervisor Then Dim s As Supervisor = DirectCast(tp, Supervisor) lstSupervisor.Items.Add(tp.nome & "-" & tp.email & "=>" & s.turno) End If If TypeOf tp Is Aluno Then Dim a As Aluno = DirectCast(tp, Aluno) lstAluno.Items.Add(tp.nome & "-" & tp.email & "=>" & a.nota & "," & a.curso) End If If TypeOf tp Is Estagiario Then Dim est As Estagiario = DirectCast(tp, Estagiario) lstEstagiario.Items.Add(tp.nome & "-" & tp.email & "=>" & est.creditos) End If Next End Using End Sub |
Neste código verificamos o tipo de cada entidade e após realizar o casting para o tipo desejado exibimos as propriedades herdades e as específicas:
Nota : Para saber mais sobre Casting no VB .NET veja o meu artigo: VB.NET - Casting
Pegue o projeto completo aqui: EF_HerancaTPT.zip
Dessa forma mostramos um exemplo básico de como implementar a herança TPT no Entity Framework .
Aguarde em breve novos artigos sobre este assunto...
Eu sei é apenas Entity Framework mas eu gosto...
Referências:
José Carlos Macoratti