Solucionado (ver solução)
Solucionado
(ver solução)
11
respostas

Relacionamento JPA @MappedSuperclass

Estou com uma dúvida, eu tenho uma superclasses Tarefa, e outras classes herdam de Tarefa, e a minha classe Produto, pode ter muitas Tarefas e estas Tarefas podem fazer parte de vários Produtos.

TAREFA

@MappedSuperclass
public abstract class Tarefa implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private String nome;

    //....

}

CLASSE FILHA DE TAREFA

@Entity(name = "abertura_missao")
public class AberturaMissao extends Tarefa {

    private LocalDate dataAbertura;

    private boolean lucroFiscal;

    private boolean lucroReal;

    private String tipoApuramento;

    private String dataAproveitamentoBeneficio;

    private LocalDate dataPrevisaoEntregaCalculo;

    private double previsaoValorDespesa;

    private int porcentagemExlcusao;

    private String observacoes;

    public AberturaMissao() {

    }
}

PRODUTO

@Entity
public class Produto {

    @Id
    private String nome;

    @ManyToMany(cascade = CascadeType.ALL)
    private List<Tarefa> tarefas = new ArrayList<Tarefa>();

    private LocalDate dataCriacao;

    public Produto() {

    }

    public String getNome() {
        return nome;
    }
}

Poderiam me ajudar no mapeamento ? está dando o seguinte erro

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class: br.com.finiciativas.fseweb.model.Produto.tarefas[br.com.finiciativas.fseweb.model.Tarefa]
11 respostas

Oi Renan, tudo bom?

Isso acontece porque estamos utilizando a entidade Tarefa apenas como um recurso de mapeamento. Isso significa que ela não é uma entidade em sí e por isso seu relacionamento ManyToMany de Tarefa e Produto não rola =/

Para esse tipo de relacionamento polimorfico, temos a parte de Inheritance da JPA que o hibernate implementa =)

Para implementar você pode trocar a anotação de MappedSuperClass para:

@Inheritance(InheritanceType.TABLE_PER_CLASS)

O parametro passado na anotação é a estrategia de geração de tabelas, você pode trocar para que seja gerada uma tabela só:

@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="TYPE")

Abraço e bons estudos =)

Olá André,

Obrigado pela resposta !

O meu mapeamento então de Tarefa na minha classe Produto então está correta depois que implemtnar o Inheritance, correto ?

Teoricamente, sim.

Só é bom lembrar que, caso você não queira um relacionamento uni-direcional, precisamos adicionar o ManyToMany de produtos na classe Tarefa também, indicando o lado dominante =)

Algo como:

    @ManyToMany(cascade=CascadeType.ALL, mappedBy="tarefas") 
    private List<Produto> produtos = new ArrayList<>();

Abraço!

Ainda não está aceitando o mapeamento ://

Está retornando o mesmo erro? Ou houve alguma mudança?

Ele está dizendo que não tem um identificador na classe filha AberturaMissao, ela não precisa , pois já herda o id do pai, mesmo assim eu coloquei para tirar a dúvida, e ai retorna o mesmo erro de antes .

Acho que deixei passar uma anotação, falta indicar a entidade Tarefa. Além disso, para evitar a necessidade do id especifico para cada entidade filha, tenta a estrategia SINGLE_TABLE. Algo como:

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE")
public abstract class Tarefa implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private String nome;

    //....

}

Aguardo retorno =)

Opa , já uma coisa, rodou, porém ele está criando a minha tabela Tarefa com os atributos da minha classe AberturaMissao, e não está criando a tabela AberturaMissao.

Tarefa

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="tarefa_nome")
public abstract class Tarefa implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private String nome;

    @ManyToMany(cascade=CascadeType.ALL, mappedBy="tarefas") 
    private List<Produto> produtos = new ArrayList<Produto>();

AberturaMissao

@Entity
@DiscriminatorValue("abertura_missao")
@Table(name="abertura_missao")
public class AberturaMissao extends Tarefa {

    private static final long serialVersionUID = 1L;

Produto

@Entity
@Table(name="produtos")
public class Produto {

    @Id
    private String nome;

    @ManyToMany(cascade = CascadeType.ALL)
    private List<Tarefa> tarefas = new ArrayList<Tarefa>();
solução!

Isso porque escolhemos a estrategia InheritanceType.SINGLE_TABLE. Esse tipo de mapeamento criará no seu banco uma unica tabela com todas as colunas necessarias de todos os casos mapeados na herança da super classe.

Ele cria uma tabela só, e diferencia a entidade pela coluna tarefa_nome.

Se o objetivo realmente é separar as tabelas a gente precisaria mudar a estrategia novamente para table_per_class. No seu caso ficaria algo parecido com:

@Entity 
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Tarefa implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private String nome;

    @ManyToMany(cascade=CascadeType.ALL, mappedBy="tarefas") 
    private List<Produto> produtos = new ArrayList<Produto>();
...
}
@Entity
@Table(name="abertura_missao")
public class AberturaMissao extends Tarefa {

    private static final long serialVersionUID = 1L;
...
}

Como a classe tarefa é abstrata, não haverá uma tabela dela no seu banco mesmo. Isso porque se ela é abstrata nunca haverá uma instancia dela no seu sistema e, por consequencia, não haverá dados para serem guardados no banco.

Sugeri a single table pois no nosso caso haverá uma tabela só de qualquer forma.

Caso você queria que haja a tabela Tarefa no seu banco, a classe não poderá ser abstrata.

Caramba jovem , você é foda ! Obrigado André ! funcionou, vou prosseguir com o desenvolvimento, caso tenha alguma duvida posto novamente aqui.

Mil obrigados pela ajuda !

System.out.println("RESOLVIDO !");

Use o @Entity na classe Pessoa e não funcionou. Mas para quem está lendo agora procurando a solução para o mesmo problema faça apenas uma alteração.

@Entity//Não utilize mais

@MappedSuperclass @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class Pessoa implements Serializable{