hibernate-orm/reference/zh-cn/modules/query_criteria.xml

377 lines
14 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<chapter id="querycriteria">
<title>
条件查询(Criteria Queries)
</title>
<para>
具有一个直观的、可扩展的条件查询API是Hibernate的特色。
</para>
<sect1 id="querycriteria-creating">
<title>创建一个<literal>Criteria</literal> 实例</title>
<para>
<literal>org.hibernate.Criteria</literal>接口表示特定持久类的一个查询。<literal>Session</literal>
<literal>Criteria</literal>实例的工厂。
</para>
<programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();]]></programlisting>
</sect1>
<sect1 id="querycriteria-narrowing">
<title>限制结果集内容</title>
<para>
一个单独的查询条件是<literal>org.hibernate.criterion.Criterion</literal>
接口的一个实例。<literal>org.hibernate.criterion.Restrictions</literal>
定义了获得某些内置<literal>Criterion</literal>类型的工厂方法。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();]]></programlisting>
<para>
约束可以按逻辑分组。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.or(
Restrictions.eq( "age", new Integer(0) ),
Restrictions.isNull("age")
) )
.list();]]></programlisting>
<programlisting><![CDATA[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();]]></programlisting>
<para>
Hibernate提供了相当多的内置criterion类型(<literal>Restrictions</literal>
子类), 但是尤其有用的是可以允许你直接使用SQL。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
.list();]]></programlisting>
<para>
<literal>{alias}</literal>占位符应当被替换为被查询实体的列别名。
</para>
<para>
<literal>Property</literal>实例是获得一个条件的另外一种途径。你可以通过调用<literal>Property.forName()</literal>
创建一个<literal>Property</literal>
</para>
<programlisting><![CDATA[
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();]]></programlisting>
</sect1>
<sect1 id="querycriteria-ordering">
<title>结果集排序</title>
<para>
你可以使用<literal>org.hibernate.criterion.Order</literal>来为查询结果排序。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();]]></programlisting>
<programlisting><![CDATA[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();]]></programlisting>
</sect1>
<sect1 id="querycriteria-associations">
<title>关联</title>
<para>
你可以使用<literal>createCriteria()</literal>非常容易的在互相关联的实体间建立
约束。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.createCriteria("kittens")
.add( Restrictions.like("name", "F%")
.list();]]></programlisting>
<para>
注意第二个 <literal>createCriteria()</literal>返回一个新的
<literal>Criteria</literal>实例,该实例引用<literal>kittens</literal> 集合中的元素。
</para>
<para>
接下来,替换形态在某些情况下也是很有用的。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.createAlias("kittens", "kt")
.createAlias("mate", "mt")
.add( Restrictions.eqProperty("kt.name", "mt.name") )
.list();]]></programlisting>
<para>
(<literal>createAlias()</literal>并不创建一个新的
<literal>Criteria</literal>实例。)
</para>
<para>
<literal>Cat</literal>实例所保存的之前两次查询所返回的kittens集合是
<emphasis>没有</emphasis>被条件预过滤的。如果你希望只获得符合条件的kittens
你必须使用<literal>returnMaps()</literal>
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.createCriteria("kittens", "kt")
.add( Restrictions.eq("name", "F%") )
.returnMaps()
.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");
}]]></programlisting>
</sect1>
<sect1 id="querycriteria-dynamicfetching" revision="1">
<title>动态关联抓取</title>
<para>
你可以使用<literal>setFetchMode()</literal>在运行时定义动态关联抓取的语义。
</para>
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.setFetchMode("mate", FetchMode.EAGER)
.setFetchMode("kittens", FetchMode.EAGER)
.list();]]></programlisting>
<para>
这个查询可以通过外连接抓取<literal>mate</literal><literal>kittens</literal>
查看<xref linkend="performance-fetching"/>可以获得更多信息。
</para>
</sect1>
<sect1 id="querycriteria-examples">
<title>查询示例</title>
<para>
<literal>org.hibernate.criterion.Example</literal>类允许你通过一个给定实例
构建一个条件查询。
</para>
<programlisting><![CDATA[Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.list();]]></programlisting>
<para>
版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。
</para>
<para>
你可以自行调整<literal>Example</literal>使之更实用。
</para>
<programlisting><![CDATA[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 comparisons
List results = session.createCriteria(Cat.class)
.add(example)
.list();]]></programlisting>
<para>
你甚至可以使用examples在关联对象上放置条件。
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.createCriteria("mate")
.add( Example.create( cat.getMate() ) )
.list();]]></programlisting>
</sect1>
<sect1 id="querycriteria-projection">
<title>投影(Projections)、聚合aggregation和分组grouping</title>
<para>
<literal>org.hibernate.criterion.Projections</literal>
<literal>Projection</literal> 的实例工厂。我们通过调用
<literal>setProjection()</literal>应用投影到一个查询。
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.rowCount() )
.add( Restrictions.eq("color", Color.BLACK) )
.list();]]></programlisting>
<programlisting><![CDATA[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();]]></programlisting>
<para>
在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为<emphasis>
分组投影</emphasis>他们也出现在SQL的<literal>group by</literal>子句中。
</para>
<para>
你可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的实现方式:
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
.addOrder( Order.asc("colr") )
.list();]]></programlisting>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.groupProperty("color").as("colr") )
.addOrder( Order.asc("colr") )
.list();]]></programlisting>
<para>
<literal>alias()</literal><literal>as()</literal>方法简便的将一个投影实例包装到另外一个
别名的<literal>Projection</literal>实例中。简而言之,当你添加一个投影到一个投影列表中时
你可以为它指定一个别名:
</para>
<programlisting><![CDATA[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();]]></programlisting>
<programlisting><![CDATA[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();]]></programlisting>
<para>
你也可以使用<literal>Property.forName()</literal>来表示投影:
</para>
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Property.forName("name") )
.add( Property.forName("color").eq(Color.BLACK) )
.list();]]></programlisting>
<programlisting><![CDATA[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();]]></programlisting>
</sect1>
<sect1 id="querycriteria-detachedqueries">
<title>离线(detached)查询和子查询</title>
<para>
<literal>DetachedCriteria</literal>类使你在一个session范围之外创建一个查询并且可以使用任意的
<literal>Session</literal>来执行它。
</para>
<programlisting><![CDATA[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();]]></programlisting>
<para>
<literal>DetachedCriteria</literal>也可以用以表示子查询。条件实例包含子查询可以通过
<literal>Subqueries</literal>或者<literal>Property</literal>获得。
</para>
<programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
.add( Property.forName("weight).gt(avgWeight) )
.list();]]></programlisting>
<programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight") );
session.createCriteria(Cat.class)
.add( Subqueries.geAll("weight", weights) )
.list();]]></programlisting>
<para>
甚至相互关联的子查询也是有可能的:
</para>
<programlisting><![CDATA[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();]]></programlisting>
</sect1>
<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
user objects - similar to setResultClass in JDO2. General use of ResultTransformer
could also be explained. -->
</chapter>