[RESOLVIDO] Hibernate + Criteria: transformar uma consulta com INNER JOIN

8 respostas
A

Olá a todos, tudo bem?

Estou com um problema para formular uma pesquisa utilizando Criteria.

Tenho as seguintes classes:

User

@Entity  
@Table(name="user")  
public class User implements Serializable, UserDetails {  
  
    private static final long serialVersionUID = -8451679170281063697L;  
      
    @Id  
    @GeneratedValue(strategy = GenerationType.AUTO)  
    @Column(name="id")  
    private Long id;  
      
    @ManyToMany(cascade={ CascadeType.ALL, CascadeType.MERGE })  
    @JoinTable(name="user_cargo",   
            joinColumns = @JoinColumn(name="user_id" , referencedColumnName="id"),   
            inverseJoinColumns = @JoinColumn(name="cargos_id" , referencedColumnName="id"))  
    private List<Cargo> cargos;  
    ...

Cargo

@Entity
@Table(name="cargo")
public class Cargo implements Serializable {
    
    private static final long serialVersionUID = 1886820991361556707L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id")
    private Long id;
    
    private String nome;
...

Quando o Hibernate mapeia estas classes ele cria a tabela no banco user_cargo com as colunas user_id e cargos_id.

Minha dúvida: a partir do id do usuário preciso consultar e retornar uma lista de nomes do(s) cargo(s) que o User possui.

Usando o SQL consigo fazendo assim:

select cargo.nome from cargo inner join user_cargo where user_id = ?;

Alguém tem ideia de como ficaria usando Criteria?

Meu método atual, conforme abaixo, esta errado. Ele compara o id do usuário diretamente com id dos cargos, não passando por essa tabela user_cargo que o Hibernate criou.

public Cargo buscarCargoPorId(long id){
        if (!session.isOpen()) {
            session = sessionFactory.openSession();
        }
        Criteria criteria = session.createCriteria(Cargo.class);
        criteria.add(Restrictions.eq("id",id));
        Cargo cargo = (Cargo) criteria.uniqueResult();
        if (session.isOpen()) {
            session.close();
        }
        return cargo;
    }

Muito obrigado.

Abraços.

8 Respostas

D
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.idEq(idDoUsuario);
User u = (User) criteria.uniqueResult();
List<Cargo> cargos = u.getCargos();
A

Obrigado pela ajuda drsmachado mas, a princípio, não subiu. Segue erro do Tomcat:

HTTP Status 500 - failed to lazily initialize a collection of role: br.com.springsecurity.model.User.cargos, could not initialize proxy - no Session

type Exception report

message failed to lazily initialize a collection of role: br.com.springsecurity.model.User.cargos, could not initialize proxy - no Session

description The server encountered an internal error that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: failed to lazily initialize a collection of role: br.com.springsecurity.model.User.cargos, could not initialize proxy - no Session
	javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
	org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:150)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
	org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
	org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
	org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
root cause

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: br.com.springsecurity.model.User.cargos, could not initialize proxy - no Session
	org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
	org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
	org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:137)
	org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:242)
	javax.faces.model.ListDataModel.isRowAvailable(ListDataModel.java:110)
	javax.faces.model.ListDataModel.setRowIndex(ListDataModel.java:185)
	javax.faces.model.ListDataModel.setWrappedData(ListDataModel.java:220)
	javax.faces.model.ListDataModel.<init>(ListDataModel.java:79)
	javax.faces.component.UIData.getDataModel(UIData.java:1804)
	javax.faces.component.UIData.setRowIndexWithoutRowStatePreserved(UIData.java:484)
	javax.faces.component.UIData.setRowIndex(UIData.java:473)
	com.sun.faces.renderkit.html_basic.TableRenderer.encodeBegin(TableRenderer.java:81)
	javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:820)
	javax.faces.component.UIData.encodeBegin(UIData.java:1118)
	com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:302)
	com.sun.faces.renderkit.html_basic.TableRenderer.renderRow(TableRenderer.java:384)
	com.sun.faces.renderkit.html_basic.TableRenderer.encodeChildren(TableRenderer.java:161)
	javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
	javax.faces.component.UIComponent.encodeAll(UIComponent.java:1756)
	javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
	javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
	javax.faces.component.UIComponent.encodeAll(UIComponent.java:1756)
	javax.faces.component.UIComponent.encodeAll(UIComponent.java:1759)
	javax.faces.component.UIComponent.encodeAll(UIComponent.java:1759)
	javax.faces.component.UIComponent.encodeAll(UIComponent.java:1759)
	com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:401)
	com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
	com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
	com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
	javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
	org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:150)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
	org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
	org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
	org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
	org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.40 logs.

Apache Tomcat/7.0.40

Segue método ajustado conforme indicação:

public List buscarCargoPorId(long id){
        if (!session.isOpen()) {
            session = sessionFactory.openSession();
        }
        Criteria criteria = session.createCriteria(User.class);  
        criteria.add(Restrictions.idEq(id));
        User user = (User) criteria.uniqueResult();
        List<Cargo> cargo = user.getCargos();
        if (session.isOpen()) {
            session.close();
        }
        return cargo;
    }

Abraços.

D

O que está acontecendo é que cargos está como LAZY, que é o padrão do fetch.
Sendo assim, quando você tenta realizar a chamada ao método getCargos, um novo select será feito.
Por alguma razão, a sessão está sendo fechada.
Não sei se cargos é a única coleção na classe User, se for, você pode colocar o fetch como EAGER e resolver isso. Se não for, você terá de pesquisar alguma forma de gerenciar a sessão.

A

Obrigado pela ajuda drsmachado.

Realmente tenho mais coleções dentro da classe User e o hibernate só aceita um fetch EAGER.

Vou ter que procurar sobre esta questão do gerenciamento de sessão.

Caso alguém tenha outra sugestão?!?!

Abraços.

D

Procure aqui. Provavelmente você vai achar algo (embora aborde JPA, serve para o hibernate).

A

Acredito não ser uma boa prática de programação, mas apenas tirei as linhas que fecham a sessão e deu certo. Lista tudo!

Vou ter que fechar a sessão na unha agora pra não ficar aberta a toa. A questão é: até onde, deixar esta sessão usada na pesquisa aberta, afeta o desempenho da aplicação? Vou ter em média 50 a 80 acessos simultâneos.

Obrigado pela ajuda!

J

alain_oliveira:
Acredito não ser uma boa prática de programação, mas apenas tirei as linhas que fecham a sessão e deu certo. Lista tudo!

Vou ter que fechar a sessão na unha agora pra não ficar aberta a toa. A questão é: até onde, deixar esta sessão usada na pesquisa aberta, afeta o desempenho da aplicação? Vou ter em média 50 a 80 acessos simultâneos.

Obrigado pela ajuda!


Sé é aplicação web abre a session antes de processar a requisição e fecha a session após sair dela. Pesquisa sobre OpenSessionInView + hibernate.

A

javaflex:
alain_oliveira:
Acredito não ser uma boa prática de programação, mas apenas tirei as linhas que fecham a sessão e deu certo. Lista tudo!

Vou ter que fechar a sessão na unha agora pra não ficar aberta a toa. A questão é: até onde, deixar esta sessão usada na pesquisa aberta, afeta o desempenho da aplicação? Vou ter em média 50 a 80 acessos simultâneos.

Obrigado pela ajuda!


Sé é aplicação web abre a session antes de processar a requisição e fecha a session após sair dela. Pesquisa sobre OpenSessionInView + hibernate.

Excelente dica. Acho que vai resolver o problema. Muito obrigado.

Criado 12 de julho de 2013
Ultima resposta 15 de jul. de 2013
Respostas 8
Participantes 3