Realizar uma consulta em JPA com uma condição WHERE em um objeto filho

25 respostas Resolvido
eclipselinkjpajava
R

Estou realizando uma consulta em JPA para me trazer uma lista de objetos e quando eu clicar em um objeto, ele vai me trazer uma lista de objetos que são relacionadas a esse objeto.

O relacionamento é esse abaixo, só que o JPA está gerando a consulta de forma automática, e eu não sei que método ele utiliza para fazer isso, então não consigo adicionar uma condição, como por exemplo: WHERE COLUNA = ?.
Existe algum método próprio do JPA como o @OrderBy que eu possa chamar e criar essa condição?

@OneToMany(cascade = CascadeType.ALL)
    @OrderBy(value = "parcela")
    @JoinColumn(name = "CODIGO_OBRA", referencedColumnName = "CODIGO")
    private List<ResPagamentoParcela> resPagamentoParcelaList;

25 Respostas

M

Rodrigo,

Pelo que eu saiba n existe anotação @where no JPA, somente pelo hibernate.

Mas vc pode utilizar o where quando for montar a query.

Pode mostrar o método q vc utiliza para fazer a busca da entidade, para poder te ajudar melhor.

R

Valeu pela resposta Matheus,

Então, vou descrever o passo a passo

Primeiro eu busco uma lista de objetos A e gero a query com o método abaixo.

javax.persistence.Query q = getEntityManager().createQuery(sb.toString());

Aqui eu consigo fazer o controle com o WHERE que eu quero para esse objeto A, só que, a partir dessa lista, eu seleciono 1 objeto que irá me trazer mais informações para edição, onde irá me trazer outra lista de objetos B, sendo assim existe o relacionamento OneToMany como eu trouxe acima.
Essa segunda consulta é gerada a partir do JPA direto, por conta do relacionamento, então não fui eu que a criei, mas sim o relacionamento, então eu não sei como colocar essa condição.

J

Usa HQL.

R

O problema é que eu não sei onde é feita a chamada dessa query para que eu possa criar outra ou alterar a que já existe.

J

https://www.tutorialspoint.com/pg/jpa/jpa_jpql.htm#

Se nao sabe onde é, debuga ou faz do zero. Eu nem usuaria jpa, faria diretamente via SQL com jdbcTemplate, muito mais eficiente e sem quebra cabeças.

R

O problema de usar uma query é que geraria uma má performance, pois traria lista de listas, da forma que eu estou fazendo, por exemplo, eu busco 10 objetos A e em cada objeto A tem 10 objetos B também, só que ele só me trás 10 objetos A e quando eu escolho 1 objeto A, ele me trás os 10 objetos de B. Se eu fizer por query, ele vai me trazer direto 10 objetos A e 100 objetos B.
Claro que na prática seria muito mais objetos dentro dessa lista, o que poderia piorar o desempenho.

R

O que faz a consulta é o relacionamento que eu mandei ali em cima. Eu só queria saber como o JPA faz isso e se tem como eu alterar de alguma forma.

J

Basta usar HQL/JPQL ou SQL.

M

Não necessariamente, vc pode utilizar o where para trazer exatamente os dados que vc precisa. Basta saber utilizar bem os conceito do SQL.

Se vc quer q ele n traga a lista, utilize o fetch = FetchType.LAZY dentro do @JoinColumn, desse modo a lista só será preenchida qndo vc precisar.

R

Mas é exatamente isso que eu estou fazendo, só que quando faço a consulta gerada pelo relacionamento eu não consigo gerar a condição que eu quero.

J

Concordo com @matheusYudi, nao tem sentido isso. Na query voce pode ter total controle do que precisa ser retornado, principalmente se for via SQL e jogando em um “DTO”, fica bem performático. Pode ser via JPQL também, embora eu ache mais engessado.

R

O problema é que eu não sei de onde a query está sendo gerada pra que eu possa alterar.

Aqui quando eu clicar no botão de edição ele me leva pra outra página.

Código do botão de edição:

<p:commandButton icon="ui-icone ui-icon-pencil" action="Edit?faces-redirect=true&amp;includeViewParams=true" styleClass="botaoCelg" >
            <f:setPropertyActionListener value="#{item}"  target="#{resObraController.selected}" />
        </p:commandButton>

E me é direcionado para outra página onde já contém as informações e a lista de objetos B com o seguinte link: http://localhost:8080/SGT-SGI/pagina/ressarcimento/Edit.jsf?codigo=3612035, só que a query que faz essa busca eu desconheço de onde venha, não há nenhuma chamada no código de uma query, por isso a minha dúvida.

M

Vamos lá, vou considerar que vc começando a aprender o conceito do JPA seja em um curso ou na faculdade e esse código já estava semi pronto.

Primeiramente, o @OneToMany por padrão vem como fetch Lazy, isso quer dizer q qndo vc faz uma consulta no banco pelo seu objeto (vou considerar q ele se chama Pagamento) ele devolve os atributos, porém se vc ver o valor da lista resPagamentoParcelaList n vai ter nenhum valor nele a não ser se sua consulta no objeto Pagamento estiver explicitamente trazendo o dado do objeto ResPagamentoParcela.

Tendo isso em mente vc precisa entender o motivo do resPagamentoParcelaList estar na sua entidade de Pagamento, faça as perguntas, eu preciso dela? Para q eu preciso dela? Qndo eu n preciso dela? Qndo eu n preciso dela?
Parece ser perguntas idiotas mas elas realmente ajudam a entender a regra e nos guiar melhor. Dps de responder essas perguntas comece a entender o código busque entender o que cada método faz, comece pelos seus controllers e vai descendo. No começo é dificil msmo, tdo acaba parecendo grego mas sempre q encontrar algo q n conheça busque na internet e até o momento q vc vai encontrar onde está sendo feito a persistência dos dados, isso vai te facilitar mto n só a alterar isso mas entender o q está acontecendo e qndo tiver outro problema estar mais fácil onde ajustar.

Não faz mto tempo q eu comecei a desenvolver por isso entendo um pouco as dores de qm está começando, sei q talvez n consegui te ajudar a resolver esse problema em especifico, mas espero q tenha dado uma clareada no conceito.

J

Pesquisa sobre jpa show sql e debuga até achar a linha que faz a query.

Dependendo do que for, pode ser mais rápido fazer do zero. Faz um SQL específico pra atender a funcionalidade e pronto, sem mistério. Nesse tempo que passou já teria feito isso.

R
@OneToMany(cascade = CascadeType.ALL)
    @OrderBy(value = "parcela")
    @JoinColumn(name = "CODIGO_OBRA", referencedColumnName = "CODIGO")
    private List<ResPagamentoParcela> resPagamentoParcelaList;

Sabe me dizer se tem alguma notação que sempre que esse relacionamento for usado, ele utilizar uma NamedQuery?

Como eu disse, eu criei a query, só que não sei onde chamar ela, porque ela é feita somente através desse relacionamento, a query gerada é SELECT * FROM PAGAMENTO WHERE CODIGO_OBRA = ?
Tem como fazer com que sempre que esse relacionamento for feito, ser através de uma query especifica?

J

Tem a anotação @where(clause = “…”), pesquise sobre.
Mas deixar isso amarrado na entidade eu acho esquisito.

Bom, já deixei minha opinião, não era pra ser complicado, e sim atender cada funcionalidade de forma específica, sem essa engenharia toda que só faz uma coisa impactar a outra e ficar nessas complicacoes de n configuracoes. Se a tela precisa da grid tal, faz um select com estrutura específica pra isso, nao tem mistério.

R

Esse é o problema, eu queria algo que fosse pra TUDO, pois esse where é pra ver se aquele item está ativo ou não, eu usaria em TODOS os relacionamento que eu tenho e resultaria em todas as telas que eu tenho, fazer isso na mão criando query para cada uma delas daria muito trabalho.

J
Solucao aceita

Cria uma view no banco que só retorna os ativos.

R

Não era o que eu estava procurando, mas resolve meu problema. :slight_smile:

Muito obrigado pela paciência.

J

O que voce está procurando pode ser a anotação @where. A view foi só minha opinião do que uso na minha experiência, por ser muito mais prático, atende n sistemas inclusive.

R

Sim, mas eu uso somente JPA e não Hibernate.

Eu usava View para outras coisas, mas não me veio a mente usar para isso também, vai ser uma mão na roda, porque vou poder usar para levantamento de dados de forma mais rápida.

J

Entendi, essa anotação é do hibernate mesmo. Entao view é mesmo a melhor solução neste caso e muitos outros.

R

@javaflex

Com a solução da VIEW, consegui resolver parte do problema, só que agora quando eu altero a coluna ativo para false, ele some na VIEW, mas no meu objeto ainda permanece.

Eu tentei usar o método refresh do JPA, só que ele tá me retornando o erro: Caused by: java.lang.IllegalArgumentException: Cannot refresh unmanaged object: br.com.celg.entidade.ResObra[ codigo=3612030 ].

Eu já li vários fóruns falando sobre, mas nenhum me ajudou.Pelo o que eu entendi é porque o objeto está no estado DETACHED e para usar o comando refresh ele precisa estar MANAGED.
Como eu faria isso? tentei dar usar o método find para buscar novamente no banco de dados e assim utilizar o refresh, mas ainda assim continua o mesmo erro.

J

Nao misture as coisas, a view é pra consulta, pra alteração use a tabela.

J

Se nao for isso, tente mapear a classe da view com @Immutable.

Criado 12 de agosto de 2019
Ultima resposta 20 de ago. de 2019
Respostas 25
Participantes 3