Select JPA and Hibernate

Asked

Viewed 2,446 times

2

I have five entities (Quotation, Sector, Partner, Items and Items), where the user will select a quotation and sector and the list of all items related to this sector will appear, along with the items that have already been launched (if they have).

I used the following select to bring the records:

String jpql = "SELECT i "
            + "FROM Itens i "
            + "INNER JOIN i.setor s "
            + "LEFT JOIN i.itensLancados il "
            + "ON il.parceiro.codParceiro = 50 AND il.cotacao.codCotacao = 1 "
            + "WHERE s.codSetor = 1";

But because the entity Itensreleased as EAGER, is bringing me all the records of this table, ignoring the restriction of partner code and quotation code.

I tried to fetch after the LEFT JOIN, but then I can’t use the ON clause, and if I try to play the restriction of the ON class to the WHERE it doesn’t work, it will filter only the data of the table Itenslancados, not bringing all the items.

Would anyone have any tips on how to solve this case?

Relationships

Quotation

@OneToMany(mappedBy = "cotacao", fetch = FetchType.LAZY)
private List<ItensLancados> itensLancados;

@ManyToMany(fetch=FetchType.LAZY)
@JoinTable(name = "cotacao_parceiro", joinColumns = @JoinColumn(name = "cotacao_id"), inverseJoinColumns = @JoinColumn(name = "parceiro_id"))
private List<Parceiro> parceiros;

@ManyToMany(fetch=FetchType.LAZY)
@JoinTable(name = "cotacao_setor", joinColumns = @JoinColumn(name = "cotacao_id"), inverseJoinColumns = @JoinColumn(name = "setor_id"))
private List<Setor> setores;

Sector

@OneToMany(mappedBy = "setor", fetch = FetchType.LAZY)
private List<Itens> itens;

@ManyToMany(mappedBy = "setores", fetch = FetchType.LAZY)
private List<Cotacao> cotacoes;

Partner

@OneToMany(mappedBy = "parceiro", fetch = FetchType.LAZY)
private List<ItensLancados> itensLancados;

@ManyToMany(mappedBy = "parceiros", fetch = FetchType.LAZY)
private List<Cotacao> cotacoes;

Items

@OneToMany(mappedBy = "itens", fetch = FetchType.LAZY)
private List<ItensLancados> itensLancados;

@ManyToOne
private Setor setor;

Points

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "cotacao_id")
private Cotacao cotacao;

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Itens itens;

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parceiro_id")
private Parceiro parceiro;

The Select you would like to convert to JPQL is as follows:

    SELECT *
FROM ITENSLANCADOS RIGHT JOIN ITENS
ON ITENSLANCADOS.ITEM_ID = ITENS.IDITENS
AND itenslancados.cotacao_id = 50
and itenslancados.parceiro_id = 1
WHERE setor_codsetor = 1

Follow the SQL generated by JPA.

select
    itens0_.idItens as idItens1_1_0_,
    itenslanca2_.cotacao_id as cotacao_1_2_1_,
    itenslanca2_.item_id as item_id2_2_1_,
    itenslanca2_.parceiro_id as parceiro3_2_1_,
    itens0_.codigoPlu as codigoPl2_1_0_,
    itens0_.descricaoItem as descrica3_1_0_,
    itens0_.eanItem as eanItem4_1_0_,
    itens0_.embalagem as embalage5_1_0_,
    itens0_.setor_codSetor as setor_co7_1_0_,
    itens0_.statusItem as statusIt6_1_0_,
    itenslanca2_.dataLancamento as dataLanc4_2_1_,
    itenslanca2_.qtdDigitada as qtdDigit5_2_1_,
    itenslanca2_.valorDigitado as valorDig6_2_1_,
    itenslanca2_.item_id as item_id2_1_0__,
    itenslanca2_.cotacao_id as cotacao_1_2_0__,
    itenslanca2_.item_id as item_id2_2_0__,
    itenslanca2_.parceiro_id as parceiro3_2_0__ 
from
    Itens itens0_ 
inner join
    Setor setor1_ 
        on itens0_.setor_codSetor=setor1_.codSetor 
left outer join
    ItensLancados itenslanca2_ 
        on itens0_.idItens=itenslanca2_.item_id 
left outer join
    ItensLancados itenslanca3_ 
        on itens0_.idItens=itenslanca3_.item_id 
inner join
    Parceiro parceiro4_ 
        on itenslanca3_.parceiro_id=parceiro4_.codParceiro 
        and (
            parceiro4_.codParceiro=1
        ) 
inner join
    Cotacao cotacao5_ 
        on itenslanca3_.cotacao_id=cotacao5_.codCotacao 
        and (
            cotacao5_.codCotacao=50
        ) 
where
    setor1_.codSetor=1
  • First of all... remove this EAGER is an option? In general, use EAGER brings much more problems than solutions.

  • You cannot make the query return launched items instead of Item?

  • Sorry, I didn’t see that. So, but reversing and placing the WHERE with the partner conditions and quotation will limit the result to only the items released and will not bring the items that were not released even using the RIGHT JOIN. I tried to do in BD the query this way (reversing the logic) and also did not roll.

  • Do you have the SQL query you’d like to do with JPQL? If so, put it on http://sqlfiddle.com/. I’m not sure what you’d like to know.

  • Check to see if you can access.. http://sqlfiddle.com/#! 15/84e71

  • Cool, but the SQL that you would like to become a JPQL, you can put there too?

  • I updated it there.. Please check if it appears please

  • SQL does not appear. Link is correct?

  • So, it is .. but I don’t know why SQL didn’t appear.. I updated there in the statement with SQL that I would like to use.

  • I want to see the result of the query, but SQL Fiddle is having difficulties... I will try again later.

Show 5 more comments

2 answers

1

Try the following:

String jpql = "SELECT i "
            + "FROM Itens i "
            + "JOIN i.setor s "
            + "LEFT FETCH JOIN i.itensLancados il "
            + "LEFT JOIN i.itensLancados ilJoin "
            + "JOIN ilJoin.parceiro parceiro WITH parceiro.codParceiro = 50"
            + "JOIN ilJoin.cotacao cotacao WITH cotacao.codCotacao = 1"
            + "WHERE s.codSetor = 1";

I can’t remember how Hibernate solves a query in which, inside the clause ON you apply other operations of JOIN (il.parceiro and il.cotacao), as you asked in the question. Actually, I didn’t even remember that JPQL supported ON... always used the WITH (which is the ONof JPQL/HQL)

  • So I did the test and this way it returns me also the materials released by other partners. I saw the return of SQL that it generates, and should really have an AND condition in the LEFT JOIN of the entity Itensreleased..

  • Yes, I’ve already removed.

  • I edited my answer. See if it works.

  • I made a small change in this select that you had sent, adding the WITH in the LEFT JOIN of the Itensreleased, but when printout on the screen, it ends up making a new select in the itenslancados with the Where of only the item, then it takes the release of another partner.

  • I’ll check now..

  • Also did not work, because in SQL generated it ends up making a LEFT JOIN only with the condition of the item code, then it ends up bringing the release of all partners, not only 50.

  • @Ismaeljunior, About coming items released from other partners, this will even occur. When you do FETCH/EAGER from i.itensLancados, all the items released from any Item the query brings in the result will come together. You have to filter this on WHERE, but I don’t understand why it didn’t help you... In general, it’s not recommended to filter out relationships that use FETCH. Some JPA frameworks do not even support alias on FETCH because of this...

  • It is then, but this what wanted to avoid. It should bring only the items referring to that partner and quotation. Pity that WITH and FETCH do not work in the same entity (Hibernate), otherwise it would solve the problem..

  • Can I comment on your question? I think you need to reverse the logic of the query.

  • @Ismaeljunior, I changed the query, see the result. It is to look like with this.

  • Hello @Dherik, I tried with this new query and the result does not return me any line. I even tried to change the joins of the partner tables and quotation to RIGHT JOIN, but also does not return. If I switch to LEFT JOIN, it brings the releases, but does not respect the partner’s condition and quotation.

  • Can you get the SQL generated by the query I went through? I want to understand what JPA is doing differently from the query I expected it to do... http://sqlfiddle.com/#! 15/84e71/8/2

  • It is updated there in the statement.

  • I saw SQL... I can think of more than one way in SQL to solve this problem, but in JPQL I’m thinking rs. Worse than SQL Fiddle is still having problems hj, it is difficult to test

  • Exactly, with SQL I also have some ways to solve, but with JPQL I’ve been skating for a few days.

Show 10 more comments

1

Let’s go to the remarks:

1st) INNER JOIN i.setor s << this JOIN is unnecessary

When you map the tables and the relationships between them in Hibernate, it already performs these joins automatically in your querys.

The JOINs are needed when we are seeking arrays, in your case the i.itensLancados

2nd) Do not use EAGER, use the LAZY

With EAGER Hibernate will always find the list you mapped before you even filter it in the query. With LAZY you have more control over your operations, as you only do how and when you want.

3rd) To search arrays using HQL you must use the LEFT JOIN FETCH or JOIN FETCH

To the Hibernate, it’s like a SELECT separate in which it seeks the elements of the array and fill it for you


Let’s go to the query:

From what I understand:

  • A sector has a list of items and a list of quotes.
  • A quote has a list of items

Then your query should search by sector: so it will bring the items of that sector, you filter the quotation list to fetch the quotation you are looking for and within the quotation you will have the items launched.

Correct?

SELECT s
  FROM Setor s
  INNER JOIN FETCH s.cotacoes cotacoes
  INNER JOIN FETCH cotacoes.parceiros parceiros= 50
  WHERE 1=1 
    AND s.codSetor = 1
    AND cotacoes.codCotacao = 1
    AND parceiros.codParceiro 

So you will have a Sector with the items of that sector, and a "quotation list" (which in case will have only the quotation with code = 1 inside), and in that quotation you will have the items

For reported error caused by Multiple bags, read these 2 references:

guj

devmedia

  • It is not recommended to make queries using the alias of a FETCH JOIN. The result of this is usually not as expected.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.