Erro com query nativa x hibernate [Resolvido]

Pessoal, tenho o seguinte método usando quary nativa do hibernate:

public List<Workflow> listaPorUsuario(GrupoWorkflow grupoWorkflow, String termo){
		String sql =   "SELECT distinct t.id_workflow," +
					   "	       		t.descricao, " +
					   "				t.quantidade_aprovacoes, " +
					   "				t.criterio_inicio, " +
					   "				t.modo_notificacao, " +
					   "				t.tempo_limite, " +
					   "				t.prioridade " +
				       "  FROM( "+
				       "      SELECT w.id_workflow, "+ 
				       "			 w.descricao,  "+
				       "			 w.quantidade_aprovacoes, "+ 
				       "			 w.criterio_inicio, "+ 
				       "			 w.modo_notificacao, "+ 
				       "			 w.tempo_limite, "+ 
				       "         	 w.prioridade "+  
				       "        FROM wf_workflow w, "+ 
				       "	 		 wf_grupo_workflow gw, "+ 
				       "			 wf_tabela_base tb, "+ 
				       "			 wf_workflow_item wi "+ 
				       "	   WHERE w.id_grupo_workflow = :grupo_workflow "+ 
				       "  		 AND w.id_workflow       = wi.id_workflow "+ 
				       " 		 AND w.id_grupo_workflow = gw.id_grupo_workflow "+ 
				       "		 AND w.id_tabela_base 	 = tb.id_tabela_base "+ 
				       "		 AND wi.username         = :username "+ 
				       
				       " UNION ALL "+
				       
				       "	  SELECT w.id_workflow, "+ 
				       "			 w.descricao,  "+
				       "			 w.quantidade_aprovacoes, "+ 
				       "			 w.criterio_inicio, "+ 
				       "			 w.modo_notificacao, "+ 
				       "			 w.tempo_limite, "+  
				       "         	 w.prioridade "+  
				       " 		FROM wf_workflow w, "+ 
				       " 		 	 wf_grupo_workflow gw, "+ 
				       "		 	 wf_tabela_base tb "+
				       "	   WHERE w.id_grupo_workflow = :grupo_workflow "+ 
				       " 		 AND w.id_grupo_workflow = gw.id_grupo_workflow "+ 
				       "		 AND w.id_tabela_base 	 = tb.id_tabela_base "+ 
				       "		 AND Not Exists (Select * From wf_workflow_item i "+ 
				       "               			  Where i.id_workflow = w.id_workflow) "+  
				       " )t ";
		
		return getSession().createSQLQuery(sql)			
	 		.addEntity(Workflow.class)
	 		.setLong("grupo_workflow", grupoWorkflow.getId_grupo_workflow())
	 		.setString("username", termo)
	 		.list();
	}

Executei esta query diretamente no banco de dados e executou normalmente, mas qdo tento executar pelo sistema, dá o seguinte erro:

16:49:42,252 ERROR [vraptor2]:253 - Servlet.service() for servlet vraptor2 threw exception
org.hibernate.exception.GenericJDBCException: could not execute query
	at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
	at org.hibernate.loader.Loader.doList(Loader.java:2148)
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2029)
	at org.hibernate.loader.Loader.list(Loader.java:2024)
	at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:118)
	at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1684)
	at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142)
	at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:164)
	at sensatta.dao.WorkflowDao.listaPorUsuario(WorkflowDao.java:80)
	at sensatta.logic.WorkflowLogic.listaPorGrupo(WorkflowLogic.java:71)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:585)
	at org.vraptor.component.DefaultLogicMethod.execute(DefaultLogicMethod.java:117)
	at org.vraptor.interceptor.ExecuteLogicInterceptor.intercept(ExecuteLogicInterceptor.java:37)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.SettingAndValidationInterceptor.intercept(SettingAndValidationInterceptor.java:131)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.InjectionInterceptor.intercept(InjectionInterceptor.java:41)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.ComponentLookupInterceptor.intercept(ComponentLookupInterceptor.java:58)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at sensatta.logic.DaoInterceptor.intercept(DaoInterceptor.java:17)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.interceptor.RegisterAttributesInteceptor.intercept(RegisterAttributesInteceptor.java:38)
	at org.vraptor.core.InterceptorsLogicFlow.execute(InterceptorsLogicFlow.java:72)
	at org.vraptor.core.VRaptorExecution.execute(VRaptorExecution.java:88)
	at org.vraptor.core.DefaultController.execute(DefaultController.java:42)
	at org.vraptor.VRaptorServlet.service(VRaptorServlet.java:70)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
	at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
	at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
	at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
	at java.lang.Thread.run(Thread.java:595)
Caused by: java.sql.SQLException: Nome de coluna inválido
	at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
	at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
	at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:269)
	at oracle.jdbc.driver.OracleStatement.get_column_index(OracleStatement.java:5971)
	at oracle.jdbc.driver.OracleResultSetImpl.findColumn(OracleResultSetImpl.java:1527)
	at oracle.jdbc.driver.OracleResultSet.getLong(OracleResultSet.java:1540)
	at org.hibernate.type.LongType.get(LongType.java:28)
	at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:113)
	at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:102)
	at org.hibernate.type.ManyToOneType.hydrate(ManyToOneType.java:95)
	at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:1983)
	at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1372)
	at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1300)
	at org.hibernate.loader.Loader.getRow(Loader.java:1197)
	at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:569)
	at org.hibernate.loader.Loader.doQuery(Loader.java:689)
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
	at org.hibernate.loader.Loader.doList(Loader.java:2145)
	... 43 more

P.S.: Na entidade Workflow exiete dois relacionamentos:

@ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "id_tabela_base"		, referencedColumnName = "id_tabela_base")
    private TabelaBase 		tabelaBase;
    
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "id_grupo_workflow"	, referencedColumnName = "id_grupo_workflow")
    private GrupoWorkflow 	grupoWorkflow;

O que pode ser este erro ?

Valew.

Só um palpite… Sou novo ainda com isso… hehe

Mas…

Não seria por que você está usando SQL no Hibernate, ao invéz de usar HQL ?

Abraço.

Rodrigo

[quote=kleins]Só um palpite… Sou novo ainda com isso… hehe

Mas…

Não seria por que você está usando SQL no Hibernate, ao invéz de usar HQL ?

Abraço.

Rodrigo[/quote]

Quando uso Query Nativa é exatamente para ter a opção de usar funções do meu banco de dados por exemplo!!! Sei que perco a portabilidade de banco de dados, mas o sistema em si não tem a intensão de usar outro banco !!! No caso uso o Hibernate, para ter maior produtividade e não portabilidade !!!

Valew.

Acho que o problema está na escrita da sua query, se não me engano para que o Hibernate possa popular os dados precisa colocar chaves {TABLE.COLUMN} nos campos de retornos, dá uma olhadinha no capitulo 10.4.4. Queries in native SQL.

Sem mais, Rodrigo.

Ops tem que colocar alias entre chaves nos campos de retorno…

Essa pergunta é complicada pois sem conhecer sua base e seus xml do hibernate é difícil.

Mas dei uma olhada e não vi onde vc setou o valor do t, w e wf. por exemplo AS hs, AS h, AS … .
É um chute no escuro sem conhecer sua base mas …

&quot;SELECT hs.*, COUNT(a.atrib_id) &gt 0 &quot; + &quot;FROM (&quot; + &quot;SELECT h.teste_id, h.num_cli, h.num_ter, &quot; + &quot;CAST(h.frq_dst_id AS VARCHAR) AS tes_id, &quot; + &quot;h.ctt_ter_id, h.ccusto_id, h.prod_teste_id, &quot; + &quot;h.ult_eve_id &quot; + &quot;FROM teste AS h &quot; + &quot;WHERE h.tipo_teste_id IN (1, 10) &quot; + &quot;AND h.ult_teste_id NOT IN (1500, 6900) &quot; + &quot;AND h.dt_teste IS NULL &quot; + where + &quot;) AS hs &quot; + &quot;LEFT JOIN atrib_testes AS a ON a.teste_id = hs.teste_id AND nome_test LIKE '$IE$%' &quot; + &quot;GROUP BY hs.teste_id, hs.num_enc_cli, &quot; + &quot;hs.num_teste_ter, hs.frq_dst_id, &quot; + &quot;hs.ctt_ter_id, hs.ccusto_id, &quot; + &quot;hs.prod_teste_id, hs.ult_teste_id&quot;;

Então galera, eu tenho um método que usa Quary Nativa e funciona certinho !!! a Diferença é que uso apenas uma tabela:

public List<Menu> listaMenu(Menu menu){
		String sql = " SELECT pai, " +
					 "        codigo, " +
					 "        tipo, " +
					 "        rpad(' ',(level*5))||descricao Descricao " +
					 "   FROM ps_menu m " +
					 "  WHERE m.pai = :codigo "+  
					 "CONNECT BY PRIOR CODIGO = PAI START WITH PAI = 0 ";

		return getSession().createSQLQuery(sql)			
		 	.addEntity(Menu.class)
		 	.setLong("codigo", menu.getCodigo())
		 	.list();
	}

Vejam que não usei chaves em alias de campos e nem AS em alias de tabelas. Ou seja, do jeito que roda direto no banco, roda por Query Nativa tb, nesta cso !!!

Agora, o pq dá o erro no caso citado no post inicial…pra mim é uma incognita !!! rsrsrsrs

Valew.

Quando vou fazer um select em mais de uma entidade no banco eu uso um Collection do tipo Object sem setar o nome da entidade, só setando o nome dos campos.
Exemplo :

[code]
Query q = session.createSQLQuery(sql);

    	q = session.createSQLQuery(sql);
             //Seta apenas o nome dos campos 
		q.setParameter("num_cliente",num_cliente, Hibernate.STRING);
		q.setParameter("cliente_id",cliente_id, Hibernate.INTEGER);

	    //Passa a Query para uma lista do tipo Object	 
        List&lt;Object[]&gt; res = q.list();
        	//Lista da classe com todos os atributos que retornam do banco
        List&lt;NomeClasse&gt; list = new ArrayList&lt;NomeClasse&gt;();
        for (Object[] h: res) {
            
        	NomeClasse d = new NomeClasse();
        	         //1º valor que retorna do banco
			d.campo_id = (Integer) h[0];
                    //Segundo valor que retorna do banco
			d.dt_post = (Date) h[1];
                    //Terceiro valor que retorna do banco
			d.cod_contrato = (String) h[2];
                          ......... //Idem para todos valores que retornarem do banco
		
        	list.add(d);
        }

//Retorna a lista que contém os objetos NomeClasse com todos os valores de retorno
return list;[/code]

[quote=sodrope]Quando vou fazer um select em mais de uma entidade no banco eu uso um Collection do tipo Object sem setar o nome da entidade, só setando o nome dos campos.
[/quote]

Fiz da maneira que vc fez no exemplo e compilou normal, mas quando vou executar o método no sistema, dá erro na seguinte linha:

d.setId_workflow ((Long)    h[0]);

Erro:

root cause

java.lang.ClassCastException: java.math.BigDecimal
	sensatta.dao.WorkflowDao.listaPorUsuario(WorkflowDao.java:90)
	sensatta.logic.WorkflowLogic.listaPorGrupo(WorkflowLogic.java:71)

Não entendi este erro, já que não to convertendo nada e estou usando o tipo correto (LONG).

O que pode ser ?

Valew.

Esse Erro é generico mas :

  • 1 Você pode estar usando o tipo da variavel diferente em algum lugar, ou na classe que vc criou pode estar diferente do banco, da uma conferida p ver se realmente é do tipo Long.

  • 2 Colocar um Cast para BigDecimal o que acho que é menos provavel e ver o que acontece, acho que o ideal é conferir o tipo de variavel no banco e na classe.

-3 Voce deve só colocar o igual sen set() “d.campo_id = (Integer) h[0];”

[quote=sodrope]Esse Erro é generico mas :

  • 1 Você pode estar usando o tipo da variavel diferente em algum lugar, ou na classe que vc criou pode estar diferente do banco, da uma conferida p ver se realmente é do tipo Long.

  • 2 Colocar um Cast para BigDecimal o que acho que é menos provavel e ver o que acontece, acho que o ideal é conferir o tipo de variavel no banco e na classe.

-3 Voce deve só colocar o igual sen set() “d.campo_id = (Integer) h[0];”[/quote]

Para todos os ID’s no sistema estou usando o tipo Long e no banco de dados Oracle o tipo NUMBER e em outras rotinas funciona normal, este erro está ocorrendo somente neste método com quary nativa!!!

Será que o Object[] h não permite o tipo Long ??

Valew.

Eu já usei com Long.

vc viu que está diferente?

d.setId_workflow ((Long) h[0]);

[quote=sodrope]Eu já usei com Long.

vc viu que está diferente?

[code]
d.setId_workflow ((Long) h[0]);

d.id_workflow = (Long) h[0];
[/quote]

Das duas maneira dá o mesmo erro !!! a diferença que para fazer a 2ª maneira, precisei declarar o id_workflow como public !!! Mas o erro persiste.

Valew.

Outra coisa que pode ser é o tipo de retorno .
Quando vc dá o select direto no banco ele tras os resultados esses mesmos resultados retornam na mesma ordem em que vc deve adicionar na sua classe e o atributo da classe deve ser do mesmo tipo do retorno ou se for diferente deve fazer um cast para o tipo do atributo da classe.

Tem certeza que o retorno da posição h[0] é o id_workflow?

na classe o id_workflow está como Long ?

dá p fazer outro teste mudar para Integer e dar um cast para Integer.

Se nenhum dessas alternativas derem certo não tenho mais ideia, mas posso te afirmar que é só algum detalhe desse tipo pois sempre uso esse tipo de select quando vou pesquisar em mais de uma entidade do banco e sempre dá certo.
Tem que conferir nos setParameter() o nome dos campos, p não confundir sempre deixo o nome e tipo dos atributos das classes igual aos das tabelas ai minimiza a possibilidade de erros.
Sugestao tente fazer com um select menor para testar.

Fiz o seguinte teste e DEU ERRO:

Fiz o seguinte teste e NÂO DEU ERRO:

Não é algum tratamento no objeto h??

Veja como ficou meu método inteiro:

public List<Workflow> listaPorUsuario(GrupoWorkflow grupoWorkflow, String termo){
		String sql =   "SELECT distinct t.* " +
				       "  FROM( "+
				       "      SELECT w.id_workflow, "+ 
				       "			 w.descricao,  "+
				       "			 w.quantidade_aprovacoes, "+ 
				       "			 w.criterio_inicio, "+ 
				       "			 w.modo_notificacao, "+ 
				       "			 w.tempo_limite, "+ 
				       "         	 w.prioridade "+  
				       "        FROM wf_workflow w, "+ 
				       "	 		 wf_grupo_workflow gw, "+ 
				       "			 wf_tabela_base tb, "+ 
				       "			 wf_workflow_item wi "+ 
				       "	   WHERE w.id_grupo_workflow = :id_grupo_workflow "+ 
				       "  		 AND w.id_workflow       = wi.id_workflow "+ 
				       " 		 AND w.id_grupo_workflow = gw.id_grupo_workflow "+ 
				       "		 AND w.id_tabela_base 	 = tb.id_tabela_base "+ 
				       "		 AND wi.username         = :username "+ 
				       
				       " UNION ALL "+
				       
				       "	  SELECT w.id_workflow, "+ 
				       "			 w.descricao,  "+
				       "			 w.quantidade_aprovacoes, "+ 
				       "			 w.criterio_inicio, "+ 
				       "			 w.modo_notificacao, "+ 
				       "			 w.tempo_limite, "+  
				       "         	 w.prioridade "+  
				       " 		FROM wf_workflow w, "+ 
				       " 		 	 wf_grupo_workflow gw, "+ 
				       "		 	 wf_tabela_base tb "+
				       "	   WHERE w.id_grupo_workflow = :id_grupo_workflow "+ 
				       " 		 AND w.id_grupo_workflow = gw.id_grupo_workflow "+ 
				       "		 AND w.id_tabela_base 	 = tb.id_tabela_base "+ 
				       "		 AND Not Exists (Select 1 From wf_workflow_item i "+ 
				       "               			  Where i.id_workflow = w.id_workflow) "+  
				       " )t ";
		
		Query q = session.createSQLQuery(sql);
     	
     	q = session.createSQLQuery(sql);
        //Seta apenas o nome dos campos 
 		q.setParameter("id_grupo_workflow"	,grupoWorkflow.getId_grupo_workflow()	, Hibernate.LONG	);
 		q.setParameter("username"			,termo									, Hibernate.STRING	);

 	    //Passa a Query para uma lista do tipo Object	 
        List<Object[]> res = q.list();
        //Lista da classe com todos os atributos que retornam do banco
        List<Workflow> list = new ArrayList<Workflow>();
        for (Object[] h: res) {
             
         	Workflow d = new Workflow();
         	System.out.println("ID_Workflow: "+(BigDecimal) h[0]);
         	System.out.println("Descricao:   "+h[1]);
         	System.out.println("Prioridade:  "+h[6]);
 			d.setId_workflow			((Long)    h[0]);
 			d.setDescricao				((String)  h[1]);
 			d.setQuantidade_aprovacoes	((Integer) h[2]);
 			d.setCriterio_inicio		((String)  h[3]);
 			d.setModo_notificacao		((Integer) h[4]);
 			d.setTempo_limite			((Long)    h[5]);
 			d.setPrioridade				((Integer) h[6]);
 		
         	list.add(d);
        }
        //Retorna a lista que contém os objetos NomeClasse com todos os valores de retorno
        return list;
	}

Valew.

Uma saida é jogar o resultado de h[0] para uma variavel e depois dar um parse nela para Integer ou Long.

Ou d.ID_Workflow = (Long) h[0].longValue() ;

[quote=sodrope]Uma saida é jogar o resultado de h[0] para uma variavel e depois dar um parse nela para Integer ou Long.

Ou d.ID_Workflow = (Long) h[0].longValue() ;[/quote]

Juliano, muito obrigado…Funcionou !!! :smiley:

Ficou assim na hora de setar:

for (Object[] h: res) {
             
         	Workflow d = new Workflow();
 			d.setId_workflow			(((BigDecimal) 	h[0]).longValue());
 			d.setDescricao				((String)  		h[1]);
 			d.setQuantidade_aprovacoes	(((BigDecimal) 	h[2]).intValue());
 			d.setCriterio_inicio		((String)  		h[3]);
 			d.setModo_notificacao		(((BigDecimal) 	h[4]).intValue());
 			d.setTempo_limite			(((BigDecimal) 	h[5]).longValue());
 			d.setPrioridade				(((BigDecimal) 	h[6]).intValue());
 		
         	list.add(d);
        }