Hibernate.orgCommunity Documentation
Table of Contents
Criteria instanceHibernate features an intuitive, extensible criteria query API.
The interfaceorg.hibernate.Criteria represents a query against a particular persistent class. TheSession is a factory forCriteria instances.
Criteria crit = sess.createCriteria(Cat.class);crit.setMaxResults(50);List cats = crit.list();
An individual query criterion is an instance of the interfaceorg.hibernate.criterion.Criterion. The classorg.hibernate.criterion.Restrictions defines factory methods for obtaining certain built-inCriterion types.
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .add( Restrictions.between("weight", minWeight, maxWeight) ) .list();Restrictions can be grouped logically.
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .add( Restrictions.or( Restrictions.eq( "age", new Integer(0) ), Restrictions.isNull("age") ) ) .list();List cats = sess.createCriteria(Cat.class) .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) ) .add( Restrictions.disjunction() .add( Restrictions.isNull("age") ) .add( Restrictions.eq("age", new Integer(0) ) ) .add( Restrictions.eq("age", new Integer(1) ) ) .add( Restrictions.eq("age", new Integer(2) ) ) ) ) .list(); There are a range of built-in criterion types (Restrictions subclasses). One of the most useful allows you to specify SQL directly.
List cats = sess.createCriteria(Cat.class) .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) ) .list(); The{alias} placeholder will be replaced by the row alias of the queried entity.
You can also obtain a criterion from aProperty instance. You can create aProperty by callingProperty.forName():
Property age = Property.forName("age");List cats = sess.createCriteria(Cat.class) .add( Restrictions.disjunction() .add( age.isNull() ) .add( age.eq( new Integer(0) ) ) .add( age.eq( new Integer(1) ) ) .add( age.eq( new Integer(2) ) ) ) ) .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) ) .list(); You can order the results usingorg.hibernate.criterion.Order.
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") .addOrder( Order.asc("name") ) .addOrder( Order.desc("age") ) .setMaxResults(50) .list();List cats = sess.createCriteria(Cat.class) .add( Property.forName("name").like("F%") ) .addOrder( Property.forName("name").asc() ) .addOrder( Property.forName("age").desc() ) .setMaxResults(50) .list(); By navigating associations usingcreateCriteria() you can specify constraints upon related entities:
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") ) .createCriteria("kittens") .add( Restrictions.like("name", "F%") ) .list(); The secondcreateCriteria() returns a new instance ofCriteria that refers to the elements of thekittens collection.
There is also an alternate form that is useful in certain circumstances:
List cats = sess.createCriteria(Cat.class) .createAlias("kittens", "kt") .createAlias("mate", "mt") .add( Restrictions.eqProperty("kt.name", "mt.name") ) .list(); (createAlias() does not create a new instance ofCriteria.)
The kittens collections held by theCat instances returned by the previous two queries arenot pre-filtered by the criteria. If you want to retrieve just the kittens that match the criteria, you must use aResultTransformer.
List cats = sess.createCriteria(Cat.class) .createCriteria("kittens", "kt") .add( Restrictions.eq("name", "F%") ) .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP) .list();Iterator iter = cats.iterator();while ( iter.hasNext() ) { Map map = (Map) iter.next(); Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS); Cat kitten = (Cat) map.get("kt");}Additionally you may manipulate the result set using a left outer join:
List cats = session.createCriteria( Cat.class ) .createAlias("mate", "mt", Criteria.LEFT_JOIN, Restrictions.like("mt.name", "good%") ) .addOrder(Order.asc("mt.age")) .list();This will return all of theCats with a mate whose name starts with "good"ordered by their mate's age, and all cats who do not have a mate. This is useful when there is a need to order or limit in the database prior to returning complex/large result sets, and removes many instances where multiple queries would have to be performed and the results unioned by java in memory.
Without this feature, first all of the cats without a mate would need to be loaded in one query.
A second query would need to retreive the cats with mates who's name started with "good" sorted by the mates age.
Thirdly, in memory; the lists would need to be joined manually.
You can specify association fetching semantics at runtime usingsetFetchMode().
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .setFetchMode("mate", FetchMode.EAGER) .setFetchMode("kittens", FetchMode.EAGER) .list(); This query will fetch bothmate andkittens by outer join. SeeSection 20.1, “Fetching strategies” for more information.
To add a restriction against a property of an embedded component, the component property name should be prepended to the property name when creating theRestriction. The criteria object should be created on the owning entity, and cannot be created on the component itself. For example, suppose theCat has a component propertyfullName with sub-propertiesfirstName andlastName:
List cats = session.createCriteria(Cat.class).add(Restrictions.eq("fullName.lastName", "Cattington")).list();Note: this does not apply when querying collections of components, for that see belowSection 17.7, “Collections”
When using criteria against collections, there are two distinct cases. One is ifthe collection contains entities (eg.<one-to-many/> or<many-to-many/>) or components (<composite-element/> ),and the second is if the collection contains scalar values (<element/>).In the first case, the syntax is as given above in the sectionSection 17.4, “Associations” where we restrict thekittenscollection. Essentially we create aCriteria object against the collectionproperty and restrict the entity or component properties using that instance.
For queryng a collection of basic values, we still create theCriteriaobject against the collection, but to reference the value, we use the special property "elements". For an indexed collection, we can also reference the index property usingthe special property "indices".
List cats = session.createCriteria(Cat.class).createCriteria("nickNames").add(Restrictions.eq("elements", "BadBoy")).list(); The classorg.hibernate.criterion.Example allows you to construct a query criterion from a given instance.
Cat cat = new Cat();cat.setSex('F');cat.setColor(Color.BLACK);List results = session.createCriteria(Cat.class) .add( Example.create(cat) ) .list();Version properties, identifiers and associations are ignored. By default, null valued properties are excluded.
You can adjust how theExample is applied.
Example example = Example.create(cat) .excludeZeroes() //exclude zero valued properties .excludeProperty("color") //exclude the property named "color" .ignoreCase() //perform case insensitive string comparisons .enableLike(); //use like for string comparisonsList results = session.createCriteria(Cat.class) .add(example) .list();You can even use examples to place criteria upon associated objects.
List results = session.createCriteria(Cat.class) .add( Example.create(cat) ) .createCriteria("mate") .add( Example.create( cat.getMate() ) ) .list(); The classorg.hibernate.criterion.Projections is a factory forProjection instances. You can apply a projection to a query by callingsetProjection().
List results = session.createCriteria(Cat.class) .setProjection( Projections.rowCount() ) .add( Restrictions.eq("color", Color.BLACK) ) .list();List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount() ) .add( Projections.avg("weight") ) .add( Projections.max("weight") ) .add( Projections.groupProperty("color") ) ) .list(); There is no explicit "group by" necessary in a criteria query. Certain projection types are defined to begrouping projections, which also appear in the SQLgroup by clause.
An alias can be assigned to a projection so that the projected value can be referred to in restrictions or orderings. Here are two different ways to do this:
List results = session.createCriteria(Cat.class) .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) ) .addOrder( Order.asc("colr") ) .list();List results = session.createCriteria(Cat.class) .setProjection( Projections.groupProperty("color").as("colr") ) .addOrder( Order.asc("colr") ) .list(); Thealias() andas() methods simply wrap a projection instance in another, aliased, instance ofProjection. As a shortcut, you can assign an alias when you add the projection to a projection list:
List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount(), "catCountByColor" ) .add( Projections.avg("weight"), "avgWeight" ) .add( Projections.max("weight"), "maxWeight" ) .add( Projections.groupProperty("color"), "color" ) ) .addOrder( Order.desc("catCountByColor") ) .addOrder( Order.desc("avgWeight") ) .list();List results = session.createCriteria(Domestic.class, "cat") .createAlias("kittens", "kit") .setProjection( Projections.projectionList() .add( Projections.property("cat.name"), "catName" ) .add( Projections.property("kit.name"), "kitName" ) ) .addOrder( Order.asc("catName") ) .addOrder( Order.asc("kitName") ) .list(); You can also useProperty.forName() to express projections:
List results = session.createCriteria(Cat.class) .setProjection( Property.forName("name") ) .add( Property.forName("color").eq(Color.BLACK) ) .list();List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount().as("catCountByColor") ) .add( Property.forName("weight").avg().as("avgWeight") ) .add( Property.forName("weight").max().as("maxWeight") ) .add( Property.forName("color").group().as("color" ) ) .addOrder( Order.desc("catCountByColor") ) .addOrder( Order.desc("avgWeight") ) .list(); TheDetachedCriteria class allows you to create a query outside the scope of a session and then execute it using an arbitrarySession.
DetachedCriteria query = DetachedCriteria.forClass(Cat.class) .add( Property.forName("sex").eq('F') ); Session session = ....;Transaction txn = session.beginTransaction();List results = query.getExecutableCriteria(session).setMaxResults(100).list();txn.commit();session.close(); ADetachedCriteria can also be used to express a subquery. Criterion instances involving subqueries can be obtained viaSubqueries orProperty.
DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class) .setProjection( Property.forName("weight").avg() );session.createCriteria(Cat.class) .add( Property.forName("weight").gt(avgWeight) ) .list();DetachedCriteria weights = DetachedCriteria.forClass(Cat.class) .setProjection( Property.forName("weight") );session.createCriteria(Cat.class) .add( Subqueries.geAll("weight", weights) ) .list();Correlated subqueries are also possible:
DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2") .setProjection( Property.forName("weight").avg() ) .add( Property.forName("cat2.sex").eqProperty("cat.sex") );session.createCriteria(Cat.class, "cat") .add( Property.forName("weight").gt(avgWeightForSex) ) .list();Example of multi-column restriction based on a subquery:
DetachedCriteria sizeQuery = DetachedCriteria.forClass( Man.class ) .setProjection( Projections.projectionList().add( Projections.property( "weight" ) ) .add( Projections.property( "height" ) ) ) .add( Restrictions.eq( "name", "John" ) );session.createCriteria( Woman.class ) .add( Subqueries.propertiesEq( new String[] { "weight", "height" }, sizeQuery ) ) .list();For most queries, including criteria queries, the query cache is not efficient because query cache invalidation occurs too frequently. However, there is a special kind of query where you can optimize the cache invalidation algorithm: lookups by a constant natural key. In some applications, this kind of query occurs frequently. The criteria API provides special provision for this use case.
First, map the natural key of your entity using<natural-id> and enable use of the second-level cache.
<class name="User"> <cache usage="read-write"/> <id name="id"> <generator/> </id> <natural-id> <property name="name"/> <property name="org"/> </natural-id> <property name="password"/></class>
This functionality is not intended for use with entities withmutable natural keys.
Once you have enabled the Hibernate query cache, theRestrictions.naturalId() allows you to make use of the more efficient cache algorithm.
session.createCriteria(User.class) .add( Restrictions.naturalId() .set("name", "gavin") .set("org", "hb") ).setCacheable(true) .uniqueResult();