JPA downcast: criteria treat vs JPQL treat

#1

I have a JPQL query that i had to transform to the criteria API. I used the criteria builder and got exactly the same results but the sql printed in the logs has an extra inner join.
Am i using the criteria API the wrong way?. Or is this the expected behavior.

The data model is simple, its just an entity ‘Elemento’ with a property ‘datosElemento’ that is associated OneToOne with an entity ‘DatosElemento’ that uses Single Table Inheritance.

@Entity
public class Elemento<T extends DatosElemento>{
 ...
  @OneToOne(mappedBy = "elemento")
  public T getDatosElemento() {
    return datosElemento;
  }
 ...
}

@Entity
@Table(name = "datos_elemento")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "nombre")
public class DatosElemento {
 ...
}

I have created a test class with both queries to test the SQL generated by hibernate.


/* Original Query */
List<Elemento> elementosJPQL
        = entityManager.createQuery("From Elemento e Join e.datosElemento de Where Treat(de as DatosEquipo).marca='abc'")
                .getResultList();

System.out.println(elementosJPQL.size());

And i observe the following generated sql ( Just one inner join with datos_elemento and it uses the discriminator column).

select
        elemento0_.id as id1_17_,
        elemento0_.descripcion as descripc2_17_,
        elemento0_.id_elementos as id_eleme7_17_,
        elemento0_.fecha_ingreso as fecha_in3_17_,
        elemento0_.identificacion as identifi4_17_,
        elemento0_.imagenes as imagenes5_17_,
        elemento0_.id_salida as id_salid8_17_,
        elemento0_.ubicacion as ubicacio6_17_ 
    from
        elemento elemento0_ 
    inner join
        datos_elemento datoseleme1_ 
            on elemento0_.id=datoseleme1_.id_elemento 
            and datoseleme1_.nombre='DatosEquipo' 
    left outer join
        datos_equipo datoseleme1_1_ 
            on datoseleme1_.id=datoseleme1_1_.id 
    where
        datoseleme1_1_.marca='abc'

Then i transformed the query with the criteria API

/* Transformed to Criteria */
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(Elemento.class);
Root from = query.from(Elemento.class);

Join datosElementoJoin = from.join("datosElemento", JoinType.LEFT);
Join datosElementoJoinTreated = cb.treat(datosElementoJoin, DatosEquipo.class);
Predicate p2 = cb.equal(datosElementoJoinTreated.get("marca"), "abc");

query = query.select(from).where(p2);

List<Elemento> elementosCriteria = entityManager.createQuery(query).getResultList();

System.out.println(elementosCriteria.size());

An here i observe several differences with the previous one as there is an extra inner join and the discrimator column is not used.

select
        elemento0_.id as id1_17_,
        elemento0_.descripcion as descripc2_17_,
        elemento0_.id_elementos as id_eleme7_17_,
        elemento0_.fecha_ingreso as fecha_in3_17_,
        elemento0_.identificacion as identifi4_17_,
        elemento0_.imagenes as imagenes5_17_,
        elemento0_.id_salida as id_salid8_17_,
        elemento0_.ubicacion as ubicacio6_17_ 
    from
        elemento elemento0_ 
    inner join
        datos_elemento datoseleme1_ 
            on elemento0_.id=datoseleme1_.id_elemento 
    inner join
        datos_elemento datoseleme2_ 
            on elemento0_.id=datoseleme2_.id_elemento 
    left outer join
        datos_equipo datoseleme2_1_ 
            on datoseleme2_.id=datoseleme2_1_.id 
    where
        datoseleme2_1_.marca=?

Again im learning to use the criteria API and i could be doing something the wrong way. So any help or ideas in this issue would be greatly appreciated.

0 Likes

#2

The Criteria API query looks fine. I suppose this is a Hibernate issue.

Try to replicate it with this test case template and open a Jira issue for it.

0 Likes