Reputation: 4011
in my database I have two tables: Person and Language. The two tables are mapped in Hibernate in a many-to-many relationship with each person speaking multiple languages.
Now I want to write a method which takes a list of languages and returns a list of people speaking ALL (logical AND) of those languages. I tried to build a criteria like:
Restrictions.in("languages", languagesList);
but this resulted back in a list of people speaking ANY (logical OR) of those languages.
I looked online and I found that there are some tricks using conjunctions and NOT EXISTS but they looked more like hacks so I wanted to check if there's a cleaner approach to achieve this.
Any suggestions? Thanks.
Upvotes: 1
Views: 236
Reputation: 11551
Try a JPQL query that first selects all the persons that speak one language and then selects from that list all the people that also speak the other language.
List<Person> ps = em.createQuery("select distinct p from Person p join p.languages l where l.languageName = 'english' "
+ " and p.id in (select distinct p.id from Person p join p.languages l where l.languageName = 'spanish' )", Person.class).getResultList();
Should work.
Upvotes: 0
Reputation: 20885
Your problem is with the understanding of the underlying relational model and not with Hibernate. The Restrictions.in
builder maps to the SQL IN
operator so your result is not unexpected at all.
In SQL this problem is interesting, too. A possible approach is this (full SQL source):
select u.user_name, count(l.language_name)
from user u
join user_language ul on u.user_name = ul.user_name
join language l on l.language_name = ul.language_name
where l.language_name in ('spanish', 'italian')
group by u.user_name
having count(l.language_name) = 2
The parameters of the query are:
'spanish', 'italian'
)2
)Unfortunately I don't have Hibernate at hand right now, but I think you'd be better off using HQL rather than the Criteria API for this.
Upvotes: 1