How to use LEFT JOIN in Hibernate Criteria
Criteria, in my opinion, is the most fantastic mechanism for querying ever created. Hibernate has an excellent API for Criteria and many users use it a lot, including me
. However by default, Hibernate Criteria uses INNER JOIN internally and depends on the situation, it doesn’t work as expected.
As you probably know, INNER and LEFT JOIN are quite different. Generally speaking, INNER JOIN is used when both sides of the associations exists, as long as LEFT JOIN is used when only the LEFT side of the relationship exists. Let’s look at a real example.
Supposing we have the following diagram:
As you can see above, there is a relationship One-To-Many between Person and Children. As usual, One Person can have none or more children, as well as a Children has only one Father (at least, biological).
Now, supposing we wanna a list of all People. If he/she has children, show up the list of them, otherwise, show up only the Person’s name. To do that, we could create an HQL like below:
Query query = getSession().createQuery("SELECT p FROM Person p LEFT JOIN p.listChildren children");
Note: We’ve used LEFT JOIN, but why? Because if the PERSON has no relationship (no children) the query MUST retrieve the values as well. If the query was like this:
Query query = getSession().createQuery("SELECT p FROM Person p INNER JOIN p.listChildren children");
The Person with no relationship (no children) will not be retrieved by the query. The INNER JOIN looks in both side of the relationship. It’s not good for that requirement.
Building the same query using Criteria
Supposing we’re going to create the same HQL above but using Criteria. The sintaxe syntax could be:
Criteria criteria = getSession().createCriteria(Person.class); criteria.addAlias("listChildren","children"); criteria.list();
Hibernate will read the code above and transform it in an HQL that uses INNER JOIN. The problem with that approach is that the Person with no Children will not be retrieved. So, how to change the default behavior from Hibernate Criteria Associations?
Using LEFT JOIN in Hibernate Criteria
Fortunatelly, there is a simple way to change the default behavior from Hibernate. Simply use the “CriteriaSpecification.LEFT_JOIN” argument. Hence, the Criteria above would be:
Criteria criteria = getSession().createCriteria(Person.class); criteria.addAlias("listChildren","children",CriteriaSpecification.LEFT_JOIN); criteria.list();
Conclusion
Criteria API is a powerful mechanism for querying in Hibernate. It can be used for simple and advanced queries. As you saw in this post, the Criteria API is also flexible. Try to use Criteria when you have dynamic parameters. Do not worry about SQL, HQL or anything else besides Objects
.
I hope this topic be useful. If you have any question or comment, fell free to leave your message below.


Brazilian guy, IT Specialist, Linux and Mac User. Work with Java/JEE and IBM Products, such as: WebSphere and DB2. Like studying Ruby, Android and IOS. Also, I like playing tennis, however I am not good enough. Write a post in this blog once a year. Follow me on twitter if you understand portuguese: @jairrillo.
Thanks, you saved me some headaches with this tip.
yeah,finally i got this…
using criteria to do left join.
tks man.
Thank you, you saved me many hours of work
Thanks dude. Cleared concepts of left join. I was struggling with it for a while. Very simple but effective usage of the Parent – Child example
Thank you for sharing !!! You saved me many hours !!!
Thank you. Neat, simple article and compact. Well written
Hi,
Could you please tell me , how to use full join with Hibernate+MySQL .
Thanks in advance.
Sridevi.
Sridevi, to use full join, simply remove the CriteriaSpecification parameter. In the example above, you use:
criteria.addAlias(“listChildren”,”children”);
Thank you. You saved my time.
Thank you man! Exaclty what I was looking for
Thank you man, really nice and short way to learn hibernate criteria specification…great
Could you please tell me, how to fetch the person whose child name is ‘childName’ using criteria.
I apply Criteriaspecification left join process-how to check the condition(ex:in sql query(left join tablename a on(a.staus=’A')) that process how to apply multiple table in jpa.
kindly tell me please
For example: If the children have a age, how can I get the average of them?
And if I need use this average in a clause where, for example, how many children are older than 11 years old. How can it works?
PS: Logically using Criteria!
thanks ,clear explanation.
Still now i has searched for joins in HQL finnaly your explanation stopped me from searching.thanks
may i know the annotations of the table?
i am trying to replicate this scenario on my project. it doesnt seem to work.
please help.
Thanks, very usefull
Hi Jair,
Great article! I see you are a big fan of hibernate criteria. I am in a bit of a predicament where I am joining two entities where one id is ‘integer’ (a) and one is ‘numeric’ (b). This is connexting to a db2 database. They join fine but when I run my queries they do not touch the db indexes. I am looking for a way to join the two entities and cast the numeric id to an integer as part of the join criteria. Do you know how to do this? The sql I want for the join is:
a.key=cast(b.key as integer)
This change makes a big difference to performance. An obvious solution is to change the datatypes in the db but unfortunately this is out of my control.
Any comments/suggestions welcome!
Cheers,
S
Thanks…Very Easy and Good Example.
Hi, I have problem to apply this.
I don’t have method addAlias.
Neither I have field LEFT_JOIN on CriteriaSpecification.
Hi Gaston,
Please, check your Hibernate version. I guess you’re using a different version from this post. Actually, the post has been written using Hibernate 3.
sintaxe or syntax
Hi Stephane,
Thanks for correcting me. The mistake has been fixed
How can i add another filter on the right table?
eg. left join children as child on p.id = child.id and child.gender=male.
Hi Pao,
You can use an ALIAS. Check it out on the documentation and you’ll see how it does work.
Hi Jair,
i’ve found createCriteria(path,alias,joinType,withClause)… but this limits me to only one criteria after the join tablename on.. What if i need to have more than one criteria in the join column?
eg.
left join children as child on p.id = child.id and child.gender=male and childage > 5 and ……
Thanks,
Pao
Hi Jair,
Seeing the example you have given above, I understand this criteria API provided Hibernate seems to list out all the columns of the PERSON table. But, what if I want to select only specific columns? How can I implement it using Hibernate Criteria?
Thanks in advance.
Hi Sayantan,
In this case, you must use another artefact called Projection.
Hi Jair,
Thanks…for Very Good Example. I need your help please help on this.
I have Two table having GUID column when I am using inner join and try to fetch the valu due to guid column i am not able to get the value its giving error due to its string.
Problem in –: Add(NHibernate.Criterion.Restrictions.Eq(“CT.ID”, “e.ID”))
see below my query. and pls tell me how to comapare the ID field of two table.
var CodeTypeSystem = session.CreateCriteria(typeof(CodeTypeSystem), “e”)
.CreateAlias(“CodeType”, “CT”, CriteriaSpecification.InnerJoin)
.Add(NHibernate.Criterion.Restrictions.Eq(“CT.Code”, codeType))
.Add(NHibernate.Criterion.Restrictions.Eq(“CT.ID”, “e.ID”))
.List();
Thanks Advance
Ganesh
Thanks Jair,
I believe you must be knowing the usage of Embedded Class which we use to define composite primary keys in an Entity class. However, it seems Hibernate Criteria is not able to read joins if I”m using Embedded objects to refer to an Entity class. Consider the following example:-
I’ve a three tables A, B & AB, where AB holds relationship between A & B and hence has a composite primary key which comprises of the primary key of A & primary key of B. I represent the relationship in hibernate as below (i’m using annotations):-
Entity class A.java
——————–
//imports…..
@Entity
@Table(name=”A”)
public class A{
private long aId;
….//other properties
private List bList; //I’ve deliberately given the name bList since using this I can get data of B.
@Id
@Column(name=”A_ID”)
public long getAId(){
return aId;
}
public void setAId(long aId){
this.aId = aId;
}
@OneToMany(mappedBy=”pk.a”)
public List getBList(){
return bList;
}
public void setBList(List bList){
this.bList = bList;
}
}
Entity class B.java
——————–
//imports…..
@Entity
@Table(name=”B”)
public class B{
private long bId;
private String name;
….//other properties
private List aList; //I’ve deliberately given the name bList since using this I can get data of A.
@Id
@Column(name=”B_ID”)
public long getBId(){
return bId;
}
public void setId(long bId){
this.bId = bId;
}
@Column(name=”B_NM”)
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
@OneToMany(mappedBy=”pk.b”)
public List getAList(){
return aList;
}
public void setAList(List aList){
this.aList = aList;
}
}
Entity class AB.java
——————–
//imports…..
@Entity
@Table(name=”AB”)
public class AB{
private AB_pk pk;
….//other properties
//Constructor to set PK object
public AB(A a, B b){
pk = new AB_pk();
pk.setA(a);
pk.setB(b);
}
@EmbeddedId
public AB_pk getPk(){
return pk;
}
public void setPk(AB_pk pk){
this.pk = pk;
}
}
Embeddable class AB_pk.java
—————————–
//imports…..
@Embeddable
public class AB{
private A a;
private B b;
public AB_pk(){ } //Empty constructor – required
@ManyToOne
@JoinColumn(name=”A_ID”)
public A getA(){
return a;
}
public void setA(A a){
this.a = a;
}
@ManyToOne
@JoinColumn(name=”B_ID”)
public B getB(){
return b;
}
public void setB(B b){
this.b = b;
}
}
Criteria code block
——————–
Criteria criteria = session.createCriteria(A.class);
criteria.createCriteria(“bList”, “ab”, CriteriaSpecification.INNER_JOIN);
criteria.createAlias(“ab.pk”, “pk”);
criteria.createCriteria(“pk.B”, “b”, CriteriaSpecification.INNER_JOIN);
ProjectionList projections = Projections.projectionList();
projections.add(Projections.property(“b.name”), “bName”);
criteria.setProjection(projections);
criteria.add(Restrictions.eq(“aId”, Long.valueOf(2733)));
List list = criteria.list();
SQL Query formed by Hibernate
——————————
SELECT b.B_NM FROM A a INNER JOIN AB ab WHERE a.A_ID = 2733
If you notice that it’s able to identify B_NM column through the Embedded ID relationship in Projections but the inner join specified in Criteria wasn’t added by hibernate in the SQL query generated by itself.
Do you know where the problem is? Am I missing something here?
Hi Jair,
Thanks…for Very Good Example. I need your help please help on this.
I have Two table having GUID column when I am using inner join and try to fetch the valu due to guid column i am not able to get the value its giving error due to its string.
Problem in –: Add(NHibernate.Criterion.Restrictions.Eq(“CT.ID”, “e.ID”))
see below my query. and pls tell me how to comapare the ID field of two table.
var CodeTypeSystem = session.CreateCriteria(typeof(CodeTypeSystem), “e”)
.CreateAlias(“CodeType”, “CT”, CriteriaSpecification.InnerJoin)
.Add(NHibernate.Criterion.Restrictions.Eq(“CT.Code”, codeType))
.Add(NHibernate.Criterion.Restrictions.Eq(“CT.ID”, “e.ID”))
.List();
Thanks Advance
Ganesh
Hi Jair,
Thanks for nice example. I have 3 tables and corresponding entities. I need to join 3 tables using criteria. I hope you can solve this problem.
Thanks,
Raghu