none
Herança com EF4 RRS feed

  • Pergunta

  • Amigos, gostaria da ajuda de vocês para solucionar um problema que estou tendo:

     

    Estou desenvolvendo uma aplicação com EF4 no VS2010 com SQLServer 2008, tudo funciona muito bem, menos quando trabalho com herança, tenho 3 classes, sendo Veículos, Carros e Motocicletas(nomes ficticios), obviamente Carros e Motocicletas herdam Veículos, até aí tudo bem, até o momento em que eu quero uma instância de Veículos e ele diz que Carros não está mapeado, estranho que já estava, pesquisando na internet vi a galera dizer que não se deve mapear classes filhas e utilizar um "TypeOf", mas, mapeando ou não, aparece o erro:

    base {System.SystemException} = {"Object mapping could not be found for Type with identity 'Sistema.Carros'."}

     

    estou tentando pegar uma instancia desta forma:

    this.carro = contexto.Carros.Where(e => e.Codigo.Equals(codigoCarro)).Single();
    

    alguem tem alguma idéia de algo que possa estar fazendo errado? 

     

    detalhe, as classes de dominio não estão sendo geradas pelo Visual Studio, somente o banco de dados

     

    Fico no aguardo!

    quinta-feira, 18 de novembro de 2010 01:30

Respostas

  • Olá,

    No Entity Framework, quando precisei fazer herança, após fazer o mapeamento e substituir uma associação por herança eu só conseguia fazer a consulta ao banco através da classe pai e só depois que eu convertia na classe filha:

    no seu caso ficaria algo do tipo:

    this.carro = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).OfType<Carro>().FirstOrDefault();

    Repare que eu faço a consulta através de veiculos (contexto.Veiculos), porém depois faço a conversão para o tipo Carro (OfType<Carro>())

    Veja:

    http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/c3fe126d-4c96-4bf1-b71f-6b0737a54011

     Atenciosamente


    Se o post foi útil marque como resposta. - Advanced Web Application - MCP - Twitter: @mpghelli
    • Sugerido como Resposta AndreAlvesLimaModerator quinta-feira, 18 de novembro de 2010 17:02
    • Marcado como Resposta MarkApollo quarta-feira, 24 de novembro de 2010 14:48
    quinta-feira, 18 de novembro de 2010 15:16
  • Olá Mark,

    Normalmente  você pode consultar através do classe pai mas não pode fazer através da classe filha, sendo necessária fazer o cast para o tipo especifico, tipo:

    CARRO

    this.carro = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).OfType<Carro>().FirstOrDefault();

    OU

    this.carro = (Carro)contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).FirstOrDefault();

    MOTO

    this.moto = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).OfType<Moto>().FirstOrDefault();

    OU

    this.moto = (Moto)contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).FirstOrDefault();

    Também deveria ser possível recuperar diretamente o veiculo sem converter para nenhum tipo:

    this.veiculo = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoVeiculo)).FirstOrDefault();

    Mais uma dica: Normalmente no Entity Framework, uma associação que pode ser convertida em herança é um Relacionamento 1 para 1 no banco de dados. Ou seja imagina a seguinte estrutura de banco:

    TABELA VEICULO                   TABELA CARRO                TABELA MOTO
    ID_VEICULO                           ID_VEICULO                       ID_VEICULO

    Repare que eu tenho o ID_VEICULO em todas as tabelas, na tabela veiculo este campo será somente chave primária, porém na tabela carro e na tabela moto o ID_VEICULO além de chave estrangeira deve ser chave primária para que possa ser gerado um relacionamento 1 para 1.

    Se você mapear estas 3 tabelas com esta estrutura pelo entity, inicialmente,  será gerado uma associação, então você deve remover a associação e adionar a herança (Carro e Moto Herdam de Veiculo, ou seja, as duas "setas" geradas pelo entity para representar herança no modelo devem estar apontando para Veiculo),  feito isto você deve remover o campo id_veiculo gerado no MODELO DO ENTITY para as entidades carro e moto.

    Espero ter ajudado



     


    Se o post foi útil marque como resposta. - Advanced Web Application - MCP - Twitter: @mpghelli
    • Marcado como Resposta MarkApollo quarta-feira, 24 de novembro de 2010 14:48
    quinta-feira, 18 de novembro de 2010 18:23
  • Olá, o Entity gera através do Edmx um classe de contexto que herda de ObjectContext, este contexto contêm referência para as classes mapeadas (ObjectSet), ao fazer qualquer consulta quando se tem herança usando o Linq Por exemplo você tem que chamar o ObjectSet da classe Pai (No seu cao Veiculo) do contexto, e só depois você irá converter para o tipo desejado como por exemplo Carro ou Moto:


    int codigoVeiculo = 1;
    
    Carro carro1 = (from c in contexto.Veiculos.OfType<Carro>() 
                      where c.Codigo.Equals(codigoVeiculo) 
                      select c).FirstOrDefault();
    


    Repare que no contexto chamo veiculos e através do OfType converto para Carro.


    Sempre trabalhei desta forma no EF 4 e nunca tive problema, seguia somente alguns passos com relação ao banco de dados e o mapeamento (edmx) gerado para o caso da herança:


    1- O Campo Chave da Tabela Veiculo deve ser Chave Estrangeira e Chave Única nas tabelas Moto e Carro para que seja gerado um relacionamento 1 para 1

    2- Ao realizar o mapeamento no entity (edmx), o modelo trará este relacionamento representado como associação, voce deve remover a associação e na toolBox do Visual Studio arrastar o componente Herança (Inheritance), onde a Classe Base será Veiculo (as setas ficarão apontando para Veiculo)

    3-No modelo do entity (edmx), remova os campos chaves das Entidades Filhas (Moto e Carro)

    4-Caso esteja usando algum recurso de Code Only ou Self Tracking do EF4 mande reegerar as classes das entidades.

    5-Realizar as consultas , utilizando o linq por exemplo, sempre deve buscar pela classe pai no contexto (classe gerado pelo entity que herda de objectContext), depois deve realizar a conversão para o tipo desejado como já demonstrado:


    int codigoVeiculo = 1;
    
    Carro carro1 = (from c in contexto.Veiculos.OfType<Carro>() 
                      where c.Codigo.Equals(codigoVeiculo) 
                      select c).FirstOrDefault();
    


    Se nada disto funcionar é provavel que o problema esteja ou na Modelagem de Dados, ou na geração da Herança pelo modelo do Entity Framework.

    Espero ter ajudado




    Se o post foi útil marque como resposta. - Advanced Web Application - MCP - Twitter: @mpghelli
    • Marcado como Resposta MarkApollo quarta-feira, 24 de novembro de 2010 14:48
    segunda-feira, 22 de novembro de 2010 22:10

Todas as Respostas

  • Olá,

    No Entity Framework, quando precisei fazer herança, após fazer o mapeamento e substituir uma associação por herança eu só conseguia fazer a consulta ao banco através da classe pai e só depois que eu convertia na classe filha:

    no seu caso ficaria algo do tipo:

    this.carro = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).OfType<Carro>().FirstOrDefault();

    Repare que eu faço a consulta através de veiculos (contexto.Veiculos), porém depois faço a conversão para o tipo Carro (OfType<Carro>())

    Veja:

    http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/c3fe126d-4c96-4bf1-b71f-6b0737a54011

     Atenciosamente


    Se o post foi útil marque como resposta. - Advanced Web Application - MCP - Twitter: @mpghelli
    • Sugerido como Resposta AndreAlvesLimaModerator quinta-feira, 18 de novembro de 2010 17:02
    • Marcado como Resposta MarkApollo quarta-feira, 24 de novembro de 2010 14:48
    quinta-feira, 18 de novembro de 2010 15:16
  • Olá, Marcus,

     

    Depois de muitas pesquisas percebi isso também, mas, o problema é que eu não consigo fazer a consulta de um veículo simplemente, isso seria possível? ou eu terei que, obrigatóriamente, consultar sempre um carro ou uma motocicleta? na realidade, na pergunta eu coloquei o código errado, seria algo do tipo:

     

    this.veiculo = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoVeiculo)).Single();
    
    

    mas, sempre dá a mensagem que coloquei lá em cima.

    mas, vlw pelo link vou dar uma olhada melhor nele assim que possível.

    quinta-feira, 18 de novembro de 2010 17:19
  • Olá Mark,

    Normalmente  você pode consultar através do classe pai mas não pode fazer através da classe filha, sendo necessária fazer o cast para o tipo especifico, tipo:

    CARRO

    this.carro = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).OfType<Carro>().FirstOrDefault();

    OU

    this.carro = (Carro)contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).FirstOrDefault();

    MOTO

    this.moto = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).OfType<Moto>().FirstOrDefault();

    OU

    this.moto = (Moto)contexto.Veiculos.Where(e => e.Codigo.Equals(codigoCarro)).FirstOrDefault();

    Também deveria ser possível recuperar diretamente o veiculo sem converter para nenhum tipo:

    this.veiculo = contexto.Veiculos.Where(e => e.Codigo.Equals(codigoVeiculo)).FirstOrDefault();

    Mais uma dica: Normalmente no Entity Framework, uma associação que pode ser convertida em herança é um Relacionamento 1 para 1 no banco de dados. Ou seja imagina a seguinte estrutura de banco:

    TABELA VEICULO                   TABELA CARRO                TABELA MOTO
    ID_VEICULO                           ID_VEICULO                       ID_VEICULO

    Repare que eu tenho o ID_VEICULO em todas as tabelas, na tabela veiculo este campo será somente chave primária, porém na tabela carro e na tabela moto o ID_VEICULO além de chave estrangeira deve ser chave primária para que possa ser gerado um relacionamento 1 para 1.

    Se você mapear estas 3 tabelas com esta estrutura pelo entity, inicialmente,  será gerado uma associação, então você deve remover a associação e adionar a herança (Carro e Moto Herdam de Veiculo, ou seja, as duas "setas" geradas pelo entity para representar herança no modelo devem estar apontando para Veiculo),  feito isto você deve remover o campo id_veiculo gerado no MODELO DO ENTITY para as entidades carro e moto.

    Espero ter ajudado



     


    Se o post foi útil marque como resposta. - Advanced Web Application - MCP - Twitter: @mpghelli
    • Marcado como Resposta MarkApollo quarta-feira, 24 de novembro de 2010 14:48
    quinta-feira, 18 de novembro de 2010 18:23
  • Ei, Márcus, obrigado pela ajuda, mas ainda não foi, devo estar dando uma de noob,rs

    Eu gerei as entidades pelo entity e mandei criar o banco, mas não busca os registros de veículos por nada, continua dando o erro

    Object mapping could not be found for Type with identity 'Sistema.Carros'

    Isso após eu pesquisar por Veículos.

     

    Hoje a noite pretendo olhar melhor, tomara que consiga passar este ponto.

    sexta-feira, 19 de novembro de 2010 14:44
  • Eh, realmente ainda nada,

     

    Refiz toda a modelagem, criei as heranças, recriei o banco, mas quando eu tento pesquisar um veiculo, ele diz que carro não está mapeado.  Sempre exibindo:

     

    Object mapping could not be found for Type with identity 'ModeloGeral.Carros'.

     

    sendo que estou pesquisando os veículos.

     

    Será que ninguem passou por insso ainda?

    sábado, 20 de novembro de 2010 20:30
  • Olá, o Entity gera através do Edmx um classe de contexto que herda de ObjectContext, este contexto contêm referência para as classes mapeadas (ObjectSet), ao fazer qualquer consulta quando se tem herança usando o Linq Por exemplo você tem que chamar o ObjectSet da classe Pai (No seu cao Veiculo) do contexto, e só depois você irá converter para o tipo desejado como por exemplo Carro ou Moto:


    int codigoVeiculo = 1;
    
    Carro carro1 = (from c in contexto.Veiculos.OfType<Carro>() 
                      where c.Codigo.Equals(codigoVeiculo) 
                      select c).FirstOrDefault();
    


    Repare que no contexto chamo veiculos e através do OfType converto para Carro.


    Sempre trabalhei desta forma no EF 4 e nunca tive problema, seguia somente alguns passos com relação ao banco de dados e o mapeamento (edmx) gerado para o caso da herança:


    1- O Campo Chave da Tabela Veiculo deve ser Chave Estrangeira e Chave Única nas tabelas Moto e Carro para que seja gerado um relacionamento 1 para 1

    2- Ao realizar o mapeamento no entity (edmx), o modelo trará este relacionamento representado como associação, voce deve remover a associação e na toolBox do Visual Studio arrastar o componente Herança (Inheritance), onde a Classe Base será Veiculo (as setas ficarão apontando para Veiculo)

    3-No modelo do entity (edmx), remova os campos chaves das Entidades Filhas (Moto e Carro)

    4-Caso esteja usando algum recurso de Code Only ou Self Tracking do EF4 mande reegerar as classes das entidades.

    5-Realizar as consultas , utilizando o linq por exemplo, sempre deve buscar pela classe pai no contexto (classe gerado pelo entity que herda de objectContext), depois deve realizar a conversão para o tipo desejado como já demonstrado:


    int codigoVeiculo = 1;
    
    Carro carro1 = (from c in contexto.Veiculos.OfType<Carro>() 
                      where c.Codigo.Equals(codigoVeiculo) 
                      select c).FirstOrDefault();
    


    Se nada disto funcionar é provavel que o problema esteja ou na Modelagem de Dados, ou na geração da Herança pelo modelo do Entity Framework.

    Espero ter ajudado




    Se o post foi útil marque como resposta. - Advanced Web Application - MCP - Twitter: @mpghelli
    • Marcado como Resposta MarkApollo quarta-feira, 24 de novembro de 2010 14:48
    segunda-feira, 22 de novembro de 2010 22:10
  • Marcus, Olá novamente, rapaz, tem algo de muito errado na minha aplicação, já refiz o modelo e nada, e já estava fazendo justamente como vc está dizendo!

     

    decidi por não trabalhar com herança por agora, já que, neste momento é um "simples" trabalho de faculdade, mas logo após vou correr atraz do problema.

     

    vlw pela ajuda!

     

     

    quarta-feira, 24 de novembro de 2010 14:48
  • Olá Pessoal,

    Muito Obrigado pela ajuda! Vou tentar implementar e ver como fica. Caso dê muito trabalho acho que vou fazer como o Mark disse e daí quando foi gerar um novo mapeamento que não haja tabelas aí sim vou explorar mais essa parte!

     

    Abraços

    quarta-feira, 22 de junho de 2011 13:30