is possible with Hibernate criteria do it?
select A.something, B.something, C.something, D.something
from A JOIN B on A.id = B.id_fk
JOIN C ON B.id = C.id_fk
JOIN D ON C.id = D.id_fk;
I have got exactly the same problem, and was able to resolve it like this:
return criteria.createCriteria(A.class)
.createCriteria("b", "join_between_a_b")
.createCriteria("c", "join_between_b_c")
.createCriteria("d", "join_between_c_d")
.add(Restrictions.eq("some_field_of_D", someValue));
Note: "b", "c" and "d" in code above refer to attribute names in A, B and C classes, correspondingly (class A has attribute b and so on).
For this solution you don't even need to have lazy and fetch parameters to be set in your A.hbm.xml.
There are some good examples in the Hibernate Reference material that show to use setFetchMode to fetch associations with an outer join.
An example is:
List books = sess.createCriteria(Book.class)
.setFetchMode("chapters", FetchMode.EAGER)
.setFetchMode("reviews", FetchMode.EAGER)
.list();
There is also information there about different fetching stragies that may be of use to you.
Try setting the fetch mode in your criteria, like:
criteria.setFetchMode(..., FetchMode.EAGER)
This creates a join query.
You may find more details here.
Yes, in fact there are several ways of doing this:
When mapping the association, set its lazyness to false and its fetch mode to join. This will affect all criteria queries.
Use setFetchMode as detailed by the other answers.
Use criteria.createAlias (or createCriteria). This also allows you to further restrict the rows you want joined.
Related
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
I am new to JPA. I am currently using JPA2.0 in WAS 8.5.5
I have a search screen where we have lot of search criteria's. Now, I have to create Query in JPA such a way that any criteria user has selected, it automatically check for that particular column in DB.
I am not able to find any solution on that. It seems to me that for every search criteria, I have to write new named Query.
Any suggestion or pointers will be appreciated.
You could do it in named query, but you would have to check every single possible criteria if it is null in order to avoid null values affect the results. Beware of unnecessary inner joins, each nullable relation should be included as left join
select e from Employee e left join e.department d
where (:name is null or e.name = :name)
and (:email is null or e.email = :email)
and (:deptId is null or d.id = :deptId)
...
However, depending on complexity of possible combinations, better option could be to not use named queries, but dynamically construct a JPQL depending on selected criteria.
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."
to select an overview from a database I have to use a statement like this:
select a1.begin, a1.end, b1.name, c1.name, d1.name, e1.name, f1.name, ...
from a2, b1, b2, c1, c2, a1
left outer join (d1 join d2 on d2.id = d1.parent and d1.user = ?) on
d1.deleted = 0 and d1.parent = a1.d1_id
left outer join (e1 join e2 on e2.id = e1.parent and e1.user = ?) on
e1.deleted = 0 and e1.parent = a1.e1_id
left outer join (f1 join f2 on f2.id = f1.parent and f1.user = ?) on
f1.deleted = 0 and f1.parent = a1.f1_id
where .... a lot more stuff...
The statement works like a charm and the database has no problem to process it really fast. Believe me, there's definitely no other way to get the required data.
Until now I was pretty proud to say, that I don't have a single word of pure EJB-QL or even SQL in our java project. But now I'm not sure if there is any way to build such a statement by using the CriteriaBuilder. I have absolutely no idea how to create an outer join with more than the single criteria or even with a nested inner join.
Any hints greatly appreciated.
Thanks
Hennes
It's hard to give specific help without knowing the object model, but I believe you want to use the join method and specify the join type. Using it you can nest joins that will use the relationship defined on the specified attribute mapping. Explain action of the criteria API can be found here:
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Criteria#Join
Eclipselink also supports the 'on' clause in JPQL and criteria queries through feature https://bugs.eclipse.org/bugs/show_bug.cgi?id=367452
first join:
criteria=session.createCriteria(mappingClass.class).createAlias("propertyName","firstAliasName");
second join:
criteria.createAlias("firstAliasName.propertyName","secondAliasName");
and so on.
That will do OFC if you are joining by mapped relations. If not than read this:Criteria API
. The simplest way to do such think it would by by HPQL or JPQL, however you will probably wont get mapped enities as result, only ResultSet with columns (but you won't get it anyway I think)
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."