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.