NHibernate features an intuitive, extensible criteria query API.
The interface NHibernate.ICriteria represents a query against a particular persistent class. The ISession is a factory for ICriteria instances.
ICriteria crit = sess.CreateCriteria<Cat>(); crit.SetMaxResults(50); List cats = crit.List();
An individual query criterion is an instance of the interface NHibernate.Expression.ICriterion. The class NHibernate.Expression.Expression defines factory methods for obtaining certain built-in ICriterion types.
IList<Cat> cats = sess.CreateCriteria<Cat>()
.Add( Expression.Like("Name", "Fritz%") )
.Add( Expression.Between("Weight", minWeight, maxWeight) )
.List<Cat>();Expressions may be grouped logically.
IList<Cat> cats = sess.CreateCriteria<Cat>()
.Add( Expression.Like("Name", "Fritz%") )
.Add( Expression.Or(
Expression.Eq( "Age", 0 ),
Expression.IsNull("Age")
) )
.List<Cat>();IList<Cat> cats = sess.CreateCriteria<Cat>()
.Add( Expression.In( "Name", new String[] { "Fritz", "Izi", "Pk" } ) )
.Add( Expression.Disjunction()
.Add( Expression.IsNull("Age") )
.Add( Expression.Eq("Age", 0 ) )
.Add( Expression.Eq("Age", 1 ) )
.Add( Expression.Eq("Age", 2 ) )
) )
.List<Cat>();There are quite a range of built-in criterion types (Expression subclasses), but one that is especially useful lets you specify SQL directly.
// Create a string parameter for the SqlString below
IList<Cat> cats = sess.CreateCriteria<Cat>()
.Add( Expression.Sql("lower({alias}.Name) like lower(?)", "Fritz%", NHibernateUtil.String )
.List<Cat>();The {alias} placeholder with be replaced by the row alias of the queried entity.
You may order the results using NHibernate.Expression.Order.
IList<Cat> cats = sess.CreateCriteria<Cat>()
.Add( Expression.Like("Name", "F%")
.AddOrder( Order.Asc("Name") )
.AddOrder( Order.Desc("Age") )
.SetMaxResults(50)
.List<Cat>();You may easily specify constraints upon related entities by navigating associations using CreateCriteria().
IList<Cat> cats = sess.CreateCriteria<Cat>()
.Add( Expression.Like("Name", "F%")
.CreateCriteria("Kittens")
.Add( Expression.Like("Name", "F%") )
.List<Cat>();note that the second CreateCriteria() returns a new instance of ICriteria, which refers to the elements of the Kittens collection.
The following, alternate form is useful in certain circumstances.
IList<Cat> cats = sess.CreateCriteria<Cat>()
.CreateAlias("Kittens", "kt")
.CreateAlias("Mate", "mt")
.Add( Expression.EqProperty("kt.Name", "mt.Name") )
.List<Cat>();(CreateAlias() does not create a new instance of ICriteria.)
Note that the kittens collections held by the Cat instances returned by the previous two queries are not pre-filtered by the criteria! If you wish to retrieve just the kittens that match the criteria, you must use SetResultTransformer(Transformers.AliasToEntityMap).
IList cats = sess.CreateCriteria<Cat>()
.CreateCriteria("Kittens", "kt")
.Add( Expression.Eq("Name", "F%") )
.SetResultTransformer(Transformers.AliasToEntityMap)
.List();
foreach ( IDictionary map in cats )
{
Cat cat = (Cat) map[CriteriaUtil.RootAlias];
Cat kitten = (Cat) map["kt"];
}You may specify association fetching semantics at runtime using SetFetchMode().
IList<Cat> cats = sess.CreateCriteria<Cat>()
.Add( Expression.Like("Name", "Fritz%") )
.SetFetchMode("Mate", FetchMode.Eager)
.SetFetchMode("Kittens", FetchMode.Eager)
.List<Cat>();This query will fetch both Mate and Kittens by outer join. See Section 19.1, “Fetching strategies” for more information.
The class NHibernate.Expression.Example allows you to construct a query criterion from a given instance.
Cat cat = new Cat();
cat.Sex = 'F';
cat.Color = Color.Black;
List<Cat> results = session.CreateCriteria<Cat>()
.Add( Example.Create(cat) )
.List<Cat>();Version properties, identifiers and associations are ignored. By default, null-valued properties and properties which return an empty string from the call to ToString() are excluded.
You can adjust how the Example is applied.
Example example = Example.Create(cat)
.ExcludeZeroes() //exclude null- or zero-valued properties
.ExcludeProperty("Color") //exclude the property named "color"
.IgnoreCase() //perform case insensitive string comparisons
.EnableLike(); //use like for string comparisons
IList<Cat> results = session.CreateCriteria<Cat>()
.Add(example)
.List<Cat>();You can even use examples to place criteria upon associated objects.
IList<Cat> results = session.CreateCriteria<Cat>()
.Add( Example.Create(cat) )
.CreateCriteria("Mate")
.Add( Example.Create( cat.Mate ) )
.List<Cat>();The class NHibernate.Expression.Projections is a factory for IProjection instances. We apply a projection to a query by calling SetProjection().
IList results = session.CreateCriteria<Cat>()
.SetProjection( Projections.RowCount() )
.Add( Expression.Eq("Color", Color.BLACK) )
.List();List results = session.CreateCriteria<Cat>()
.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 be grouping projections, which also appear in the SQL group by clause.
An alias may optionally be assigned to a projection, so that the projected value may be referred to in restrictions or orderings. Here are two different ways to do this:
IList results = session.CreateCriteria<Cat>()
.SetProjection( Projections.Alias( Projections.GroupProperty("Color"), "colr" ) )
.AddOrder( Order.Asc("colr") )
.List();IList results = session.CreateCriteria<Cat>()
.SetProjection( Projections.GroupProperty("Color").As("colr") )
.AddOrder( Order.Asc("colr") )
.List();The Alias() and As() methods simply wrap a projection instance in another, aliased, instance of IProjection. As a shortcut, you can assign an alias when you add the projection to a projection list:
IList results = session.CreateCriteria<Cat>()
.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();IList results = session.CreateCriteria<DomesticCat>("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();The DetachedCriteria class lets you create a query outside the scope of a session, and then later execute it using some arbitrary ISession.
DetachedCriteria query = DetachedCriteria.For<Cat>()
.Add( Expression.Eq("sex", 'F') );
ISession session = ....;
ITransaction txn = session.BeginTransaction();
IList results = query.GetExecutableCriteria(session).SetMaxResults(100).List();
txn.Commit();
session.Close();A DetachedCriteria may also be used to express a subquery. ICriterion instances involving subqueries may be obtained via Subqueries .
DetachedCriteria avgWeight = DetachedCriteria.For<Cat>()
.SetProjection( Projections.Avg("Weight") );
session.CreateCriteria<Cat>()
.Add( Subqueries.Gt("Weight", avgWeight) )
.List();DetachedCriteria weights = DetachedCriteria.For<Cat>()
.SetProjection( Projections.Property("Weight") );
session.CreateCriteria<Cat>()
.add( Subqueries.GeAll("Weight", weights) )
.list();Even correlated subqueries are possible:
DetachedCriteria avgWeightForSex = DetachedCriteria.For<Cat>("cat2")
.SetProjection( Projections.Avg("Weight") )
.Add( Expression.EqProperty("cat2.Sex", "cat.Sex") );
session.CreateCriteria<Cat>("cat")
.Add( Subqueries.Gt("weight", avgWeightForSex) )
.List();