assuming I have following two tables (Cats with Kittens):
==== Cat.java ====
@Id @GeneratedValue( strategy = GenerationType.IDENTITY )
private long id;
@Column( unique = true, nullable = false )
private String name;
@OneToMany @JoinColumn( name = "cat_id" )
private List<Kitten> kitten;
==== Kitten.java ====
@Id @GeneratedValue( strategy = GenerationType.IDENTITY )
private long id;
@Column( unique = true, nullable = false )
private String name;
with the following data
Cat(id, name)
Cat(1, "Cat 1")
Cat(2, "Cat 2")
Kitten(id, cat_id, name)
Kitten(1, 1, "Kitten 1")
Kitten(2, 1, "Kitten 2")
Kitten(3, 2, "Kitten 3")
Kitten(3, 2, "Bad Kit")
Now I would like to see all cats which have a kitten whose name contains "kitten".
list = sess().createCriteria( Cat.class ).createAlias( "kitten", "kitten" )
.add( Restrictions.like( "kitten.name", "%kitten%" ) ).list();
The previous command is not very nice because of the join I will get duplicate entries and for example count and maxresult are not working. This is a well documented problem and it is mentioned to use subqueries instead.
I'm thinking of something like this (but with Criteria-Api):
from Cat where id in
(select cat_id from Kitten where name like '%kitten%')
This doesn't work because hibernate doesn't give me access to "cat_id" and I don't want to make it bidirectional just for this query.
Your query, if you just add a projection to get the cat ID, is the subquery you'd like to use. So you just need the following:
DetachedCriteria acceptedCatIds = DetachedCriteria.forClass(Cat.class);
acceptedCatIds.createAlias("kitten", "kitten")
.add(Restrictions.like("kitten.name", "%kitten%" ))
.setProjection(Projections.id());
Criteria acceptedCats = session.createCriteria(Cat.class)
acceptedCats.add(Subqueries.propertyIn("id", acceptedCatIds));