Hibernate Criteria aPI Multiselect - java

If I use Hibernate Criteria API like:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root<OneEntity> entityOneRoot = criteriaQuery.from(OneEntity.class);
Root<TwoEntity> entityTwoRoot = criteriaQuery.from(TwoEntity.class);
criteriaQuery.multiselect(OneEntity, TwoEntity);
Do I need to use EQUAL-restriction (as ON-restriction in SQL) for equaling IDs between both tables (entities)? Because of Cartesian product of both tables?
criteriaQuery.where(criteriaBuilder.equal(OneEntity.get("fk_id"), TwoEntity.get("id")));
I mean... In SQL using join we need to use on-clausule like:
select * from table_1 t1, table_2 t2 where t1.t2_id=t2.t1_id;
But I can't find information about it in API Criteria.

From JPA 2.1 specification, chapter 4.4.5 Joins:
An inner join may be implicitly specified by the use of a cartesian
product in the FROM clause and a join condition in the WHERE
clause. In the absence of a join condition, this reduces to the
cartesian product.
The main use case for this generalized style of join is when a join
condition does not involve a foreign key relationship that is mapped
to an entity relationship.
Example:
SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize
In general, use of this style of inner join (also referred to as
theta-join) is less typical than explicitly defined joins over
relationships.
Since JPQL is works the same way as Criteria API then equal restriction is needed in your query.

Related

'ORDER BY' in JPQL-query adds 'CROSS JOIN' to produced sql thus reducing final results

I’m to create query with ordering by field of related entity, like this:
SELECT p FROM Patient p ORDER BY p.doctor.name
And sql-query that Hibernate builds based on that of JPQL uses CROSS JOIN with condition (effectively, inner join):
select patient0_.id as id1_1_, patient0_.doctor_id as doctor_i3_1_, patient0_.name as name2_1_
from patient patient0_ cross join doctor doctor1_
where patient0_.doctor_id=doctor1_.id
order by doctor1_.name
As a side-effect, all patients with nulls in ‘doctor’ field are excluded from result set. Is there any option I can switch to hint Hibernate to use LEFT JOIN in such cases? Can’t such a behavior be considered a bug? From common sense’ point, just adding ordering shoud not affect result count.
Example is intentionally simplified. In real world it’s a dynamically built criteria-query with variable set of filters and sortings. So I can not work it around and use explicit LEFT JOIN in JPQL.
I reproduced behavior of simplified example in version 5.3.9.Final and in latest 5.4.15.Final.
Appreciate any help.
You should use explicit join instead of hibernate implicit join.
SELECT p FROM Patient p left join fetch p.doctor d ORDER BY d.name
If there is lazy relation and it is not wanted that doctor is loaded, fetch should not be used.
SELECT p FROM Patient p left join p.doctor d ORDER BY d.name
This is how the implicit join is defined for JPA, as an inner join. So if you want to use left join semantics, you will have to use a an explicit left join.
If you want something more dynamic, I can recommend you take a look at a query builder like Blaze-Persistence that has left join semantics for implicit joins.
Here is a Spring WebMvc example application that supports dynamic filtering and sorting for paginated datatables: https://github.com/Blazebit/blaze-persistence/tree/master/examples/spring-data-webmvc

How to select in Hibernate criteria if there is no relationship between the tables? [duplicate]

I'd like to use Hibernate's criteria api to formulate a particular query that joins two entities. Let's say I have two entities, Pet and Owner with a owner having many pets, but crucially that association is not mapped in the Java annotations or xml.
With hql, I could select owners that have a pet called 'fido' by specifying the join in the query (rather than adding a set of pets to the owner class).
Can the same be done using hibernate criteria? If so how?
Thanks,
J
This is indeed possible with criteria:
DetachedCriteria ownerCriteria = DetachedCriteria.forClass(Owner.class);
ownerCriteria.setProjection(Property.forName("id"));
ownerCriteria.add(Restrictions.eq("ownername", "bob"));
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.add(Property.forName("ownerId").in(ownerCriteria));
Update: This actually performs a sub-query instead of a join but it allows you to use Criteria on two entities that do not have a hibernate relationship defined.
My understanding is that if you do this using HQL, you are creating a Cartesian join with a filter, rather than an inner join. Criteria queries do not support doing this.
In NHibernate you can use subqueries which are defined as DetachedCriteria. Not sure if it works the same in Java, most probably it is the same:
DetachedCriteria pets = DetachedCriteria.For<Pet>("pet")
.SetProjection(Projections.Property("pet.ownername"))
.Add(/* some filters */ );
session.CreateCriteria(typeof(Owner))
.Add(Subqueries.PropertyIn("name", pets);
Assumed that it is joined using the name of the owner.
Criterion ownerCriterion = Restrictions.sqlRestriction(SELECT ownerId FROM Owner WHERE ownerName ='bob');
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.createCriteria("ownerId").add(ownerCriterion);
There's a SQLCriterion, which you can give arbitrary SQL, and add to your Criteria. In the SQL string, the token {alias} "will be replaced by the alias of the root entity."

OR clause in LEFT_JOIN in hibernate criteria

How can provide OR clause in LEFT_JOIN in hibernate criteria.
Criteria mainCrit=hibernateSession.createCriteria("Main.class");
Criteria aPropertyCrit=mainCrit.createCrieria("child",CriteriaSpecification.LEFT_JOIN);
It generates sql as
select this_.Id,this_childId....
from main as this_
left join child as child1_ on child1_ .id=this_.childId
where.....
And I need to generate the sql as
select this_.Id,this_childId....
from main as this_
left join child as child1_ on child1_.id=this_.childId or child_.ParentId=this_.childId
where.....
How do I provide OR clause in LEFT_JOIN in above criteria.
The extending of the JOIN ... ON part, could be done, even with Criteria API. But only to be more restrictive, i.e. adding the AND part.
Take a look on the overloads of the createCriteria method, mostly the last parameter withClause:
Criteria createCriteria(String associationPath,
String alias,
JoinType joinType,
Criterion withClause)
throws HibernateException
Create a new Criteria, "rooted" at the associated entity, assigning the given alias and using the specified join type.
Parameters:
associationPath - A dot-seperated property path
alias - The alias to assign to the joined association (for later reference).
joinType - The type of join to use.
withClause - The criteria to be added to the join condition (ON clause)
In fact, any other approach (e.g. adding the OR), is breaking the mapping principal, introducing the ability to have the cross join at the end. see Hibernate criteria: Joining table without a mapped association

Criteria Query with multiple cascaded joins involved

I have three entities: Block, Viewand TargetBlockand want to create a JPA Criteria query for the following sql.
select * from Block INNER JOIN TargetBlock tb ON tb.blockID = b.blockID INNER JOIN view v ON tb.viewID = v.viewID
Block has many views and many TargetBlocks.
For documentation of the Criteria API see,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Criteria#Join

Hibernate criteria: Joining table without a mapped association

I'd like to use Hibernate's criteria api to formulate a particular query that joins two entities. Let's say I have two entities, Pet and Owner with a owner having many pets, but crucially that association is not mapped in the Java annotations or xml.
With hql, I could select owners that have a pet called 'fido' by specifying the join in the query (rather than adding a set of pets to the owner class).
Can the same be done using hibernate criteria? If so how?
Thanks,
J
This is indeed possible with criteria:
DetachedCriteria ownerCriteria = DetachedCriteria.forClass(Owner.class);
ownerCriteria.setProjection(Property.forName("id"));
ownerCriteria.add(Restrictions.eq("ownername", "bob"));
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.add(Property.forName("ownerId").in(ownerCriteria));
Update: This actually performs a sub-query instead of a join but it allows you to use Criteria on two entities that do not have a hibernate relationship defined.
My understanding is that if you do this using HQL, you are creating a Cartesian join with a filter, rather than an inner join. Criteria queries do not support doing this.
In NHibernate you can use subqueries which are defined as DetachedCriteria. Not sure if it works the same in Java, most probably it is the same:
DetachedCriteria pets = DetachedCriteria.For<Pet>("pet")
.SetProjection(Projections.Property("pet.ownername"))
.Add(/* some filters */ );
session.CreateCriteria(typeof(Owner))
.Add(Subqueries.PropertyIn("name", pets);
Assumed that it is joined using the name of the owner.
Criterion ownerCriterion = Restrictions.sqlRestriction(SELECT ownerId FROM Owner WHERE ownerName ='bob');
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.createCriteria("ownerId").add(ownerCriterion);
There's a SQLCriterion, which you can give arbitrary SQL, and add to your Criteria. In the SQL string, the token {alias} "will be replaced by the alias of the root entity."

Categories

Resources