Jpql - join com relacionamento inverso [resolvido]

4 respostas
M

Pessoal, Boa Tarde!

Muito raramente utilizo JPQL no meu dia-a-dia e estou com dificuldade numa query (exemplificada no Ex2):
Pelo que entendi para fazer um JOIN em JPQL basta referenciarmos a Tabela atual com o atributo que representa a outra

Ex 1: Carregar as habilitações de Tarefas para um Usuário
[list]TarefaUsuario (ManyToOne) Usuario (“TarefaUsuario possui o id do usuário”)[/list] " SELECT DISTINCT t" " FROM TarefaUsuario t" " JOIN t.usuario u" // Aqui foi tranquilo, pois tenho o atributo Usuário em TarefaUsuario " WHERE" " u.usuarioPK = :usuarioPK"

Minha dúvida é, e quando a tabela de cima não tiver um atributo que representa a de baixo e sim o contrário?
Ex2: (Onde enfrento o problema) Carregar as habilitações de Tarefas de um Grupo a qual um usuário pertence.
[list]TarefaUsuario (ManyToOne) Grupo (TarefaUsuario possui o id do Grupo)[/list] [list]Grupo (ManyToOne) GrupoUsuario (GrupoUsuario possui o id do Grupo)[/list][list] GrupoUsuario (ManyToOne) Usuario (GrupoUsuario possui o id do Usuario)[/list] " SELECT" " DISTINCT tru" " FROM " " TarefaUsuario tru" " JOIN tru.Grupo grp" " JOIN GrupoUsuario.grupo gus" // Problema está aqui, "grp" (Grupo) não tem o id de (GrupoUsuario) e sim o inverso (relacionamento é de baixo p/ cima) " JOIN gus.Usuario uso" " WHERE" " uso.segUsuarioPK = :segUsuarioPK"

Quando Rodo a Aplicação estoura a seguinte exception = [color=red]org.hibernate.hql.ast.QuerySyntaxException: Invalid path: ‘null.grupo’[/color] - Provavelmente linha 6 do EX2

Espero que tenham entendido minha dúvida.
Desde já Agradeço…

4 Respostas

A

Não dá para pegar as tarefas pelo Usuário?
Tipo Usuario.GrupoUsuario.Grupo.TarefaUsuario…

SELECT   
   DISTINCT tru   
 FROM    
   Usuario.GrupoUsuario.Grupo.TarefaUsuario tru
 WHERE bla...bla...bla

Sei lá…

M

asandrob,

Primeiramente agradeço por responder ao tópico.

Então cara, não rolou pq no Objeto Usuario não tenho o atributo GrupoUsuário, este é o Relacionamento;
Tabela Usuário

  • Não contém FK;
    Tabela Grupo
  • Não contém FK;
    Tabela GrupoUsuário
  • id_Usuario:FK;
  • id_Grupo:FK;
    Tabela TarefaUsuario
  • id_Grupo:FK;

Esse é o Select original em Firebird (Funciona Legalzinho):

" SELECT" " DISTINCT tru.*" " FROM TarefaUsuario tru" " INNER JOIN Grupo gpr" " ON gpr.Grupo_id = tru.Grupo_id" " INNER JOIN GrupoUsuario gu" " ON gu.ID_Grupo = gpr.ID_Grupo" " INNER JOIN Usuario uso" " ON uso.Usuario_Id = gu.Usuario_Id" " WHERE" " tru.Status = 'ATV'" " AND uso.Usuario_Id = :Usuario_Id" " AND uso.Status = 'ATV'"

O engraçado é que tenho certeza que a solução é simples mais não consigo encontra-la.
Quero seguir o padrão do JPQL no meu projeto, mais é meio tenso cara.

Obrigado !!!

P

Podes ter as relações nas duas classes.

ManyToOne em uma, OneToMany na outra.

M

Por isso que eu digo...
Se desconfiar de uma solução para seu problema, tente aplicar antes de duvidar da capacidade da Tecnologia que está utilizando.

Fiz exatamente como pmlm disse e funfou, na verdade havia pensado nisso como uma possível solução mas confesso que achei loucura
pois no Objeto Grupo tenho uma Lista GrupoUsuario.
Pensei: Como o Hibernate vai carregar e varrer o a lista de GrupoUsuario e buscar as referencias? Se o mapeamento estiver certinho ele faz numa boa.

Segue a Solução: 1. Mapear as duas Entidades Na classe abaixo, adiciono o mapeamento (nessa Tabela realmente tenho o id do Grupo)
public class GrupoUsuario implements Serializable {
    @ManyToOne(fetch= FetchType.EAGER)
    @JoinColumns({
        @JoinColumn(name = "ID_USUARIO", referencedColumnName= "ID_USUARIO", insertable=false, updatable=false)
    })
    private Usuario usuario;
    
    @ManyToOne(fetch= FetchType.EAGER)
    @JoinColumns({
        @JoinColumn(name= "ID_GRUPO", referencedColumnName="ID_GRUPO", insertable=false, updatable=false)
    })
    private Grupo grupo;
Na Tabela representada abaixo não tenho o id do Grupo, porém fiz o mapeamento contrário com @OneToMany com o mappedBy (que indica o lado fraco da Entidade)
public class Grupo implements Serializable {
    @OneToMany(mappedBy = "Grupo")
    private List<GrupoUsuario> grupoUsuarioList;
2. Acertar a linha 06 da query conforme o novo relacionamento:
" SELECT"
"   DISTINCT tru"
" FROM "
"   TarefaUsuario tru"
"   JOIN tru.grupo grp"
"   JOIN grp.grupoUsuarioList gus" // Ajuste da Query chamando o Atributo @OneToMany 
"   JOIN gus.segUsuario uso"
" WHERE"
"   uso.segUsuarioPK = :segUsuarioPK"

Olhando pelo console, a query está igualzinha a que apliquei antes com o SQL...

Aí fica uma curiosidade: Apliquei o relacionamento Bidirecional, certo? A idéia é sempre fazer isso?
Agradeço aos dois pela colaboração, me ajudaram bastante.

Criado 20 de janeiro de 2012
Ultima resposta 20 de jan. de 2012
Respostas 4
Participantes 3