Pergunta

Tenho um problema com meu modelo de domínio JPA. Estou apenas tentando brincar com herança simples para a qual uso uma classe base simples e uma subclasse de clientes. De acordo com a documentação oficial (JPA e Eclipselink), só preciso do ID-ATIBUTION/COLUNA na classe base. Mas quando executo meus testes, sempre recebo um erro dizendo que o cliente não tem @id?

Primeiro, pensei que o problema está na visibilidade do atributo de ID, porque foi privado primeiro. Mas mesmo depois que eu o mudei para protegido (para que a subclasse tenha acesso direto), ele não está funcionando.

Pessoa:

@Entity @Table(name="Persons")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE")
public class Person {

    @Id
    @GeneratedValue
    protected int id;
    @Column(nullable = false)
    protected String firstName;
    @Column(nullable = false)
    protected String lastName;

Cliente:

@Entity @Table(name = "Customers")
@DiscriminatorValue("C")
public class Customer extends Person {

    //no id needed here

Estou ficando sem idéias e recursos para se olhar. Deve ser um problema bastante simples, mas eu simplesmente não vejo.

Foi útil?

Solução

Eu mesmo resolvi, criando um MappedSuperclass

@MappedSuperclass
public abstract class EntityBase{
   @Id
   @GeneratedValue
   private int id;

   ...setter/getter
}

Todas as entidades estão herdando desta classe. Ainda estou me perguntando por que os tutoriais não mencionam isso, mas talvez melhore com as implementações do JPA 2.

Outras dicas

Eu tive exatamente o mesmo problema. Para a subclasse que eu estava recebendo:

Entity class [...] has no primary key specified. It should define either an @Id, @EmbeddedId or an @IdClass.

No meu caso, acabou que esqueci de adicionar minha aula de raiz em persistence.xml.

Certifique -se de ter pessoas e clientes definidas em:

<persistence>
  <persistence-unit>
    ...
    <class>package.Person</class>
    <class>package.Customer</class>
    ...
  </persistence-unit>
</persistence>

Eu sei que isso é antigo, mas mesmo assim válido. Eu tive o mesmo problema. No entanto, o @MaPEDSuperclass não é o mesmo que uma única tabela de herança. O MappedSuperclass criará tabelas separadas para cada uma das subclasses (como eu entendo)

Não sei exatamente o porquê, mas quando só tenho uma aula herdada, não tive problemas. No entanto, uma vez que adicionei o segundo e o terceiro, recebi o mesmo erro. Quando especifiquei a anotação @id na tabela criança, ela começou a funcionar novamente.

Meu layout era simples, informações de contato para empresas, agentes e clientes.

Tabela pai:

...
@Entity
@Inheritance(strategy= InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="USER_TYPE", length=10, discriminatorType= DiscriminatorType.STRING)
@Table(name="CONTACTS")
public abstract class AbstractContact implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @Column (length=10, nullable=false)
    protected String mapType;
    @Column (length=120, nullable=false)
    protected String mapValue;
...

Contatos do agente

@Entity
@DiscriminatorValue("Agent")
public class AgentContact extends AbstractContact implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    protected Agents agent;
}

Contato da empresa:

@Entity
@DiscriminatorValue("Company")
public class CompanyContact extends AbstractContact implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    protected Companies company;

}

Contatos do cliente:

@Entity
@DiscriminatorValue("Client")
public class ClientContact extends AbstractContact implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;
    //Client table not built yet so... no mapping
}

A tabela de clientes ainda não foi criada, portanto, não há informações de mapeamento, mas você entendeu.

Eu queria compartilhar a descrição do MySQL, mas o prompt de comando do Windows é muito inútil para cortar/copiar/colar! Em essencialmente, ITS: ID (int PRI) user_type (varchar (10)) user_id (int) maptype (varchar (10)) mapValue (varchar (120))

Eu ainda tenho que configurar todos os testes, mas até agora parece bom (temo que se eu esperar até depois de fazer todos os testes, esquecerei de postar isso)

A JPA conhece duas maneiras diferentes de aplicar a herança:

  • Ingeriu a herança da mesa
  • Herança de tabela única

Com a herança de tabela única, você precisará de uma coluna discriminadora para distinguir entre as linhas da tabela.

Com a herança de tabela unida, cada classe recebe sua própria tabela para que nenhuma coluna discriminadora seja necessária.

Eu acho que o seu problema é que você misturou os dois conceitos. Então também:

  • Defina as colunas discriminadoras e use `heretancetype.single_table` e não Use `@tabela` em subclasses
  • ou use `heritanceType.Joined`, mas não Especifique a coluna e os valores discriminadores!

Pode haver outra razão para esse erro ao usar Glassfish / Eclipselink: Eclipselink <2.6.0 tem um Bug desagradável causando classes com expressões de lambda nela para ser ignorada. Isso pode levar a erros confusos, como o mencionado aqui, ou outros erros semelhantes (por exemplo, o Eclipselink pode dizer que uma classe com uma anotação @Entity não é uma entidade).

O Glassfish 4.1 inclui o Eclipselink 2.5.x, então esse bug (e muitos outros) o morderá se estiver usando o Glassfish. Eu estava usando esta versão em vez de 4.1.1 devido a outro bug que impossibilitou o uso da validação nos serviços da Web REST. Fique o mais longe possível de Glassfish, se quiser manter sua sanidade.

Você pode obter esse tipo de erro quando não gera o esquema de banco de dados baseado em suas entidades. Se esse é o caso:

1º - sua superclasse deve sempre ter um @id

2º - Sua subclasse deve ter alguma coluna que identifique a classe estendida (super classe @id)

3º - Solução mais simples para o caso apresentado acima seria adicionar um ID da coluna à tabela de subclasse, com a restrição de chave estrangeira correspondente.

Espero que isso ajude alguém! Afirmativo!

Como já vi algumas respostas que podem ajudar, mas não uma resposta completa, tentarei fornecer uma.

Como afirma a resposta aceita, você deve declarar a herança na classe base. Existem 4 maneiras diferentes de fazer isso:

  • @MapDSuperclass

Mapeará cada classe de concreto para a tabela

  • @Inheritance (estratégia = heretancetype.table_per_class)

Semelhante ao @mappedsuperclass, mas a superclasse também é uma entidade

  • @Iritance (estratégia = heretancetype.single_table)

Todas as classes de concreto serão mapeadas pela mesma tabela

  • @Iritance (estratégia = heretancetype.Joined)

Cada aula recebe sua própria mesa. Os campos unidos serão mapeados pela tabela para a superclasse abstrata.

Você pode ler mais sobre as estratégias de herança da JPA aqui:
https://www.thoughts-on-java.org/complete-guide-fheritance-strategies-jpa-hibernate/


Se a estrutura da classe estiver dividida em diferentes projetos, talvez seja necessário declarar a superclasse em sua persistência.xml, como tk.luczak declarou em sua resposta

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top