开发者

Hibernate: Criteria API: Query entities which do not contain a specified element in a CollectionOfElements?

开发者 https://www.devze.com 2023-03-07 23:55 出处:网络
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\".

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号