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

[Dúvida] Exception ao usar InheritanceType.SINGLE_TABLE

Pessoal, ao utilizar a estratégia SINGLE_TABLE é lançado a seguinte exception. Como solucionar?

Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [br.com.alura.loja.modelo.Produto] : Discriminator: at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154) at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1542) at org.hibernate.query.Query.getResultList(Query.java:165) at br.com.alura.loja.dao.ProdutoDAO.buscaTodos(ProdutoDAO.java:28) at br.com.alura.loja.testes.CadastroDeProduto.buscaProdutos(CadastroDeProduto.java:28) at br.com.alura.loja.testes.CadastroDeProduto.main(CadastroDeProduto.java:17) Caused by: org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [br.com.alura.loja.modelo.Produto] : Discriminator: at org.hibernate.loader.Loader.getInstanceClass(Loader.java:1941) at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1722) at org.hibernate.loader.Loader.getRow(Loader.java:1615) at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:745) at org.hibernate.loader.Loader.processResultSet(Loader.java:1008) at org.hibernate.loader.Loader.doQuery(Loader.java:964) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354) at org.hibernate.loader.Loader.doList(Loader.java:2838) at org.hibernate.loader.Loader.doList(Loader.java:2820) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2652) at org.hibernate.loader.Loader.list(Loader.java:2647) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:506) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:396) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1404) at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1565) at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1533) ... 4 more

5 respostas

Oi!

Provavelmente o produto que foi salvo com id = 1 na sua tabela de produtos esteja com problema na coluna de discriminator. Faz um select nessa tabela e manda aqui um print e também os códigos das suas classes.

Oi Rodrigo, tudo bem? Segue a tabela e os códigos solicitados. Desde já agradeço a ajuda.

Tabela Produtos

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Classe Produto

@Entity
@Table(name = "produtos")

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Produto {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String nome;
    private String descricao;
    private BigDecimal preco;
    private LocalDate dataDeCadastro = LocalDate.now();

    @ManyToOne(fetch = FetchType.LAZY)
    private Categoria categoria;

    public Produto() {
    }

    public Produto(String nome, String descricao, BigDecimal preco, Categoria categoria) {
        this.nome = nome;
        this.descricao = descricao;
        this.preco = preco;
        this.categoria = categoria;
    }

    // getters e setters

}

Classe Livro

@Entity
@Table(name = "livros")
public class Livro extends Produto {

    private String autor;
    private Integer numeroDePaginas;

    public Livro() {
    }

    public Livro(String autor, Integer numeroDePaginas) {
        this.autor = autor;
        this.numeroDePaginas = numeroDePaginas;
    }
    
    // getters e setters

}

Classe Informatica

@Entity
@Table(name = "informatica")
public class Informatica extends Produto {

    private String marca;
    private String modelo;

    public Informatica() {
    }

    public Informatica(String marca, String modelo) {
        this.marca = marca;
        this.modelo = modelo;
    }

    // getters e setters

}

Classe ProdutoDAO

public class ProdutoDAO {

    private EntityManager em;

    public ProdutoDAO(EntityManager em) {
        this.em = em;
    }

    public void cadastra(Produto produto) {
        this.em.persist(produto);
    }

    public Produto buscaPorId(Long id) {
        return em.find(Produto.class, id);
    }

    public List<Produto> buscaTodos() {
        String jpql = "SELECT p FROM Produto p";
        return em.createQuery(jpql, Produto.class).getResultList();
    }

    public List<Produto> buscaPorNome(String nome) {
        String jpql = "SELECT p FROM Produto p WHERE p.nome = :nome";
        return em.createQuery(jpql, Produto.class).setParameter("nome", nome).getResultList();
    }

    public List<Produto> buscaPorNomeEPreco(String nome, BigDecimal preco) {
        String jpql = "SELECT p FROM Produto p WHERE p.nome = :nome AND p.preco = :preco";
        return em.createQuery(jpql, Produto.class).setParameter("nome", nome).setParameter("preco", preco).getResultList();
    }

    public List<Produto> buscaPorNomeDaCategoria(String nome) {
        return em.createNamedQuery("produtosPorCategoria", Produto.class).setParameter("nome", nome).getResultList();
    }

    public BigDecimal buscarPrecoDoProdutoComNome(String nome) {
        String jpql = "SELECT p.preco FROM Produto p WHERE p.nome = :nome";
        return em.createQuery(jpql, BigDecimal.class).setParameter("nome", nome).getSingleResult();
    }

}

Classe de Teste

public class CadastroDeProduto {
    public static void main(String[] args) {
        EntityManager em = JpaUtil.getEntityManager();
        ProdutoDAO produtoDao = new ProdutoDAO(em);

        List<Produto> todosProdutos = produtoDao.buscaTodos();
        todosProdutos.forEach(produto -> System.out.println(produto.getNome()));
    }
}

Está faltando a coluna DTYPE no "tabelão" de produtos.

Vou chutar que essa sua tabela já exisita com esses registros, você alterou o mapemanto para herança SINGLE_TALBE, mas não rodou o código para o Hiberante criar as tabelas do zero. Nesse caso, sua tablea precisa ter mais uma coluna, que, por padrão se chama DTYPE.

Isso, a tabela já existe com os registros. Quando eu rodo o código com o SINGLE_TABLE , aquela exception é lançada. A JPA chega a criar a coluna DTYPE, porém a exception é lançada em seguida.

Olha o console.

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

solução!

Perfeito. As tableas são alteradas, mas como elas já tem registros eles ficam com valor null nessa nova coluna e com isso o Hibernate não sabe diferenciar o tipo de cada produto.

Pra resolver precisa apagar todos os registros ou atualizar todos eles para adicionar o valor dessa coluna em cada um.