Hibernate gerando List de Object

13 respostas
maiconramones

Buenas povo, vou descrever um erro que eu nunca vi antes…

Tenho duas classes (coloquei só os atributos importantes):

A classe Propriedade tem esse trecho de código:

@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
	@JoinColumn(name = "id_valor", nullable = true)
	public Valor getValor() {
		return valor;
	}

A classe Valor tem esse trecho:

@OneToMany(mappedBy = "valor", cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    public List<Propriedade> getPropriedades() {
        return propriedades;
    }

Quanto faço uma query o sql gerado:

select this_.id as id5_1_, this_.createDate as createDate5_1_, this_.updateDate as updateDate5_1_, this_.version as version5_1_, this_.conteudo as conteudo5_1_, this_.rotulo as rotulo5_1_, this_.id_valor as id7_5_1_, valor2_.id as id2_0_, valor2_.createDate as createDate2_0_, valor2_.updateDate as updateDate2_0_, valor2_.version as version2_0_, valor2_.rotulo as rotulo2_0_, valor2_.valor as valor2_0_ from propriedade this_ left outer join valor valor2_ on this_.id_valor=valor2_.id limit ?

O problema é:
Essa query retorna um List de Object :shock: sendo que meu PersistenceClass é Propriedade, e o mais estranho é que cada Object tem um array :? . Onde na primeira posição tem uma entidade Valor e na segunda tem uma entidade Propriedade.

Alguém tem alguma idéia do porque o hibernate está assumindo esse comportamento?

Valeu

13 Respostas

R

Você pode mostrar o HQL ou Criteria usado para executar a consulta?

maiconramones

Opa claro, só que eu tenho uma hierarquia de daos e tal então eu vou postar o trecho de código que a gente manipula que é utilizando o DetachedCriteria:

Considere sortOrder e sortField como do tipo String que são passados por parâmetro.

int size = getRowCount(dc).intValue();
        if (sortField != null && !sortOrder.equals(SortOrder.UNSORTED)) {
            if (sortOrder.equals(SortOrder.ASCENDING)) {
                dc.addOrder(Order.asc(sortField));
            } else {
                dc.addOrder(Order.desc(sortField));
            }
        List<T> data = this.findByCriteria(dc, first, pageSize);
        }

@Override
    public List<T> findByCriteria(DetachedCriteria dc, int first, int maxResult) {
        Criteria criteria = dc.getExecutableCriteria(getSession());
        criteria.setFirstResult(first);
        criteria.setMaxResults(maxResult);
        return criteria.list();
    }

Valeu

maiconramones

Extra, Extra, Extra…

Realizando alguns testes somente com Hibernate sem JPA o problema não ocorre…

Agora eu vou ter que descobrir que implementação está gerando esse “bug” se é que ele é um bug mesmo…

Alguém tem alguma idéia do por onde começar??

Valeu

R

Não sei exatamente como você montou o seu Criteria, mas, se fosse HQL, diria que você está retornando dados disjuntos “SELECT a, b FROM ClasseA a, ClasseB b WHERE a.id = b.id” em vez de instâncias únicas “SELECT a FROM ClasseA”. Criteria oferece esse tipo de recurso?

alias

Eu diria o mesmo. Alias essa query nao está retornando um cartesiano?

Ao montar o seu Criteria, voce está passando o SuaClasse.class, correto?

Não obstante, tente isso aqui:

criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
maiconramones

Opa, desculpem pela demora.

Consegui fazer algumas evoluções e isolar o problema, o fato é que eu desconsiderei um trecho de código que era chamado através de um método, achei que era um código inofensivo mas pelo visto não é…

Eu tenho um método que é chamado pra dizer a quantidade de registros retornados pela query (usado numa tela que tem paginação) e esse cara que está bugando a query.

Pra facilitar a vida de quem está tentando ajudar e pra facilitar os meus testes eu coloquei tudo em um único método com os devidos comentários.

O bug está no trecho que realiza um rowCount, se eu comentar o devido trecho a query retorna os objetos corretos.

DetachedCriteria dc = DetachedCriteria.forClass(getPersistenceClass());
        
//      Esse é trecho que busca a quantidade de linhas, se comentar até a linha 10 a query funciona
        Criteria criteria = dc.getExecutableCriteria(getSession());
        criteria.setProjection(Projections.rowCount());
        criteria.setFirstResult(0);
        criteria.setMaxResults(1);
        Long result = (Long) criteria.uniqueResult();
        criteria.setProjection(null);
//     Fim do trecho que gera o bug
        
        int size = result.intValue(); 
        
        if (sortField != null && !sortOrder.equals(SortOrder.UNSORTED)) {
            if (sortOrder.equals(SortOrder.ASCENDING)) {
                dc.addOrder(Order.asc(sortField));
            } else {
                dc.addOrder(Order.desc(sortField));
            }
        }
        
        Criteria criteria2 = dc.getExecutableCriteria(getSession());
        criteria2.setFirstResult(first);
        criteria2.setMaxResults(10);
    	
        
       List<Propriedade> propriedades = criteria2.list();

      // Aqui vai um return utilizando DataModel

Não consigo visualizar o porque do rowCount estar interferindo na query.

Valeu

R

Estranho. Vai um palpite: tente não reaproveitar a instância [dc] ao criar [criteria2].

maiconramones

Opa,

Roger pelo pesquisei tem várias pessoas com o mesmo problema, conseguir de alguma maneira reaproveitar a DetachedCriteria…

De qualquer forma achei muito estranho esse bug e queria entender o porque.

R

Entrando novamente no território dos palpites, já que não uso Criteria, suponho que as alterações realizadas no objeto [criteria] tenham de alguma maneira afetado o objeto [dc] ou sua semântica de execução. Por isso minha sugestão para recriar “do zero” o objeto [criteria2], sem reaproveitar [dc]. Esse chute teve sucesso, ou estou falando bobagem? :slight_smile:

maiconramones

Consegui mas de uma forma bizarra :shock:

Serializando a DetachedCriteria… mas não sei porque eu to achando que isso não é muito elegante hehehe

DetachedCriteria dc = DetachedCriteria.forClass(getPersistenceClass());
        
//      Esse é trecho que busca a quantidade de linhas, se comentar até a linha 10 a query funciona
        Criteria criteria = dc.getExecutableCriteria(getSession());
        criteria.setProjection(Projections.rowCount());
        criteria.setFirstResult(0);
        criteria.setMaxResults(1);
        Long result = (Long) criteria.uniqueResult();
        criteria.setProjection(null);
//     Fim do trecho que gera o bug
        
        int size = result.intValue(); 

       DetachedCriteria  dc2 = null;
        
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         try {
			ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
			outputStream.writeObject(dc);
			
			ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
			dc2 = (DetachedCriteria) objectInputStream.readObject();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
        Criteria criteria = dc2.getExecutableCriteria(getSession());
        criteria.setProjection(Projections.rowCount());
        criteria.setFirstResult(0);
        criteria.setMaxResults(1);
        Long result = (Long) criteria.uniqueResult();
        criteria.setProjection(null);
        
        int size = result.intValue();
        
        if (sortField != null && !sortOrder.equals(SortOrder.UNSORTED)) {
            if (sortOrder.equals(SortOrder.ASCENDING)) {
                dc.addOrder(Order.asc(sortField));
            } else {
                dc.addOrder(Order.desc(sortField));
            }
        }
        
        Criteria criteria2 = dc.getExecutableCriteria(getSession());
        criteria2.setFirstResult(first);
        criteria2.setMaxResults(10);
    	
        
       List<Propriedade> propriedades = criteria2.list();

      // Aqui vai um return utilizando DataModel
maiconramones

Prezados descobri realizando mais testes que se eu inverter a lógica de primeiro fazer a query e depois fazer a Projection do rowcount funciona.

Mas sigo sem entender o real problema de bugar a query ao inverter essa ordem. :frowning:

R

Pode ser um bug no próprio Hibernate. Qual é a versão que você está usando? Bom saber que você pôde tirar o hack da serialização, não é interessante manter esse tipo de coisa no código-fonte.

maiconramones

roger_rf cara encontrei a explicação para o bug no fórum do hibernate.

Na verdade primeiramente queria esclarecer que não é um bug do hibernate.

O que ocorre é que a projection default é a própria classe da Criteria, como ela foi setada para null o hibernate não sabe quem é a projection e trás uma lista de object.

Então nesse caso invertendo a ordem funciona.

Valeu Roger pela parceria nessa thread hehehehe

abraço

Criado 19 de setembro de 2011
Ultima resposta 21 de set. de 2011
Respostas 13
Participantes 3