Hibernate: Criteria API: Query entities which do not contain a specified element in a CollectionOfElements?
Let's say I have the following two classes; User and Location. I want to create a DetachedCriteria to query the user table, and return all users who do not have a location with the name "xyz".
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@CollectionOfElements
Set<Location> locations;
}
@Entity
public class Location{
@Id
@GeneratedValue(strategy = Generatio开发者_运维技巧nType.AUTO)
Long id;
@Column
String name;
}
The following code will return all users who DO have a location with name "xyz" set:
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
dc.createCriteria("locations")
dc.add(Restrictions.eq("name", "xyz"));
If I change to Restrictions.ne(), that doesn't work, because it will only return users who actually have locations set. Also, if there are a bunch of locations set for a user, it will duplicate that user over and over.
Any ideas?
Using the entities User and Location as described in your original post:
1) Check if the associated locations is empty.
Junction or = Restrictions.disjunction();
or.add(Restrictions.isEmpty("locations"));
2) Create an associated criteria for locations using a LEFT_JOIN and an alias to be used in the "ne" restriction. The LEFT_JOIN is required so we still get User records back even if the locations relationship is empty.
userCriteria.createCriteria("locations", "loc", Criteria.LEFT_JOIN);
or.add(Restrictions.ne("loc.name", "xyz"));
3) Add the disjunction to the the original User criteria.
userCriteria.add(or);
You'll probably need to use some combination of Restrictions.and()
, Restrictions.not()
, Restrictions.or()
and Restrictions.in()
to get your inverse-logic to work right. Check http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/criterion/Restrictions.html - it can definitely be done!
To ensure you only get at-most-one User
, use a Distinct
projection (http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/criterion/Distinct.html) via the Projections.distinct()
factory method (http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/criterion/Projections.html)- i.e.:
dc.setProjection(Projections.distinct(Projections.property("id")));
Something like that should do what you need.
精彩评论