该文档介绍了不同查询机制的使用。文档中的代码都通过Junit测试过。
内容:
1. Query by criteria
2. ODMG Object Query Language(OQL)
3. JDO queries
通过criteria查询:
在本节中,你将学到如何使用criteria进行查询。相应的类放在org.apache.ojb.broker包
中。使用criteria查询既可以得到整个对象(如person),也可以使用report queries得
到一行数据
一个查询主要包含下面两部分:
1. 得到相应类的对象
2. 一系列带有ORDER BY和GROUP BY的条件列表
OJB提供了一个QueryFactory类来创建一个新的查询。虽然所有的query类的构造方法是公
共的,但是我们还是建议使用QueryFactory来建立一个新的查询:
Query q = QueryFactory.newQuery(Person.class, crit);
每个条件就代表一个SQL-Where语句。
Criteria crit = new Criteria();
crit.addEqualTo("firstname", "tom");
crit.addEqualTo("lastname", "hanks");
Query q = QueryFactory.newQuery(Person.class, crit);
相应的SQL语句如下:
Select ... FROM PERSON Where FIRSTNAME = "tom" AND LASTNAME = "hanks";
查询条件:
OJB提供了所有SQL-comparator的条件选择。在大多数情况下,你不需要自己直接去实现如
EqualToCriteria之类的类。Criteria类提供相应的方法,有如下四种:
1. 通过比较相应字段的值来创建criteria:如addEqualTo(“firstname”,”tom”)
2. 通过比较两个字段来创建criteria:如addEqualToField(“firstname”,”other_fi
eld”)
3. 通过检查是否为空值来创建criteria:如addIsNull(“firstname”)
4. 创建一个模糊的sql criteria:如addSql(”REVERSE(name) like ‘re%’”)
下面是比较一个字段值的方法:
addEqualTo
addLike
addGreaterOrEqualThan
addGreaterThan
addLike
addBetween ,该方法需要两个参数
addIn , 该方法使用Collection类作为值参数
下面是比较两个字段的方法,都是以…field结尾:
addEqualToField
addGreaterThanField
and of course there negative forms
in/not in
有些数据库限制了IN语法的参数数目
如有有限制,OJB会把IN语句拆开成几个语句,下面的例子把限制数目设成了3:
Select ... FROM Artikel A0 Where A0.Kategorie_Nr IN ( ? , ? , ? )
or A0.Kategorie_Nr IN ( ? , ? ) orDER BY 7 DESC
IN的限制能够在OJB.properties中被定义:
...
# The SqlInLimit entry limits the number of values in IN-sql
# statement, -1 for no limits. This hint is used in Criteria.
SqlInLimit=200
...
and/or
上面得到的查询条件都是“并“的关系,有时候需要获得”与“的关系,如下:
Criteria crit1 = new Criteria();
crit1.addLike("firstname", "%o%");
crit1.addLike("lastname", "%m%");
Criteria crit2 = new Criteria();
crit2.addEqualTo("firstname", "hank");
crit1.addOrCriteria(crit2);
Query q = QueryFactory.newQuery(Person.class, crit1);
Collection results = broker.getCollectionByQuery(q);
对应的SQL语句如下:
Select ... Where (FIRSTNAME LIKE "%o%") AND LASTNAME
LIKE "%m%" or FIRSTNAME = "hank"
排序和分组:
下面的方法能够用来排序和分组:
addOrderByAscending(String anAttributeName);
addOrderByDescending(String anAttributeName);
addGroupBy(String anAttributeName); 该方法用于report queries
你也可以进行多重排序和分组,重复调用addOrderBy就可以:
crit = new Criteria();
crit.addOrderByDescending("id");
crit.addOrderByAscending("lastname");
query = new QueryByCriteria(Person.class, crit);
broker.getCollectionByQuery(query);
上面的代码将查询所有的Persons,并按id的降序排列,lastname的升序排列。该查询将产
生如下的SQL语句:
Select A0.ID,A0.FIRSTNAME,A0.LASTNAME FROM
PERSON A0 orDER BY 1 DESC, 3
如果你不使用lastname而用LASTNAME,那么新的LASTNAME将会自动被创建:
Select A0.ID,A0.FIRSTNAME,A0.LASTNAME,LASTNAME FROM PERSON A0 orDER BY 1 DESC,
4
如果有多个表都含有LASTNAME,SQL语句就会报错,所以最好使用和属性名一样。
联接:
在path expressions中(relationship.attribute)声明的联接在criteria中会被OJB自
动处理。Path expressions支持1:1,1:n,m:n多种关系。
下面的例子查找属于Liquors产品组的所有文章。文章和产品组的关系是在Article类中
的productGroup关系来建立的:
<!-- Definitions for org.apache.ojb.ojb.broker.Article -->
<class-descriptor
class="org.apache.ojb.broker.Article"
proxy="dynamic"
table="Artikel"
>
...
<reference-descriptor
name="productGroup"
class-ref="org.apache.ojb.broker.ProductGroup"
>
<foreignkey field-ref="productGroupId"/>
</reference-descriptor>
</class-descriptor>
<class-descriptor
class="org.apache.ojb.broker.ProductGroup"
proxy="org.apache.ojb.broker.ProductGroupProxy"
table="Kategorien"
>
...
<field-descriptor
name="groupName"
column="KategorieName"
jdbc-type="VARCHAR"
/>
...
</class-descriptor>
path expressions包含了productGroup和groupName间1:1的关系
Criteria crit = new Criteria();
crit.addEqualTo("productGroup.groupName", "Liquors");
Query q = QueryFactory.newQuery(Article.class, crit);
Collection results = broker.getCollectionByQuery(q);
如果path expressions指向一个有限制的类,那么查询条件就变成了Ored。下面的例子
查询所有文章名以F开头的ProductGroups。Path expressions 声明了allArticlesInGr
oup来表示Articles的限制:Books和CDs:
Criteria crit = new Criteria();
crit.addLike("allArticlesInGroup.articleName", "F%");
Query q = QueryFactory.newQuery(ProductGroup.class, crit, true);
Collection results = broker.getCollectionByQuery(q);
SQL语句如下:
Select DISTINCT A0.KategorieName,A0.Kategorie_Nr,A0.Beschreibung
FROM Kategorien A0
INNER JOIN Artikel A1 ON A0.Kategorie_Nr=A1.Kategorie_Nr
LEFT OUTER JOIN BOOKS A1E0 ON A0.Kategorie_Nr=A1E0.Kategorie_Nr
LEFT OUTER JOIN CDS A1E1 ON A0.Kategorie_Nr=A1E1.Kategorie_Nr
Where A1.Artikelname LIKE 'F%' or
A1E0.Artikelname LIKE 'F%' or
A1E1.Artikelname LIKE 'F%'
Prefetched 关系:
能够使通过关系查询对象的查询次数最小化。在我们的测试中,我们指定ProductGroup
s和Articles有一对多的关系。当查询ProductGroups,通过一个查询获得ProductGroup
s,对于每个ProductGroup我们再通过查询获得它的Articles。
OJB试着通过prefetched关系将属于ProductGroups的所有Ariticles通过一个查询得到。
让我们来看看为什么一个查询基本上不能实现:
Criteria crit = new Criteria();
crit.addLessOrEqualThan("groupId", new Integer(5));
crit.addOrderByDescending("groupId");
crit.addPrefetchedRelationship("allArticlesInGroup");
Query q = QueryFactory.newQuery(ProductGroup.class, crit);
Collection results = broker.getCollectionByQuery(q);
第一个查询获得所有匹配的ProductGroups:
Select ... FROM Kategorien A0 Where
A0.Kategorie_Nr <= ? orDER BY 3 DESC
第二个查询从第一个查询的结构中获得属于ProductGroups的Articles:
Select ... FROM Artikel A0 Where A0.Kategorie_Nr
IN ( ? , ? , ? , ? , ? ) orDER BY 7 DESC
获得了所有相关的Articles后,该方法还不支持对关系使用Arrays。
查询对象:
OJB查询返回完全的对象,这就意味着所有的实例变量会被赋值,所有的自动获得关系会
被加载。到现在为止,还没有方法能够只获得部分的对象(如仅仅得到personde 的fir
stname和lastname)
Report查询:
Report查询适合获得一行数据,但是不使真正意义上的商业对象。一行数据就是一个对
象数组,通过这些查询你能够定义什么样的对象属性你希望在一行数据中存在。属性名
也可以包括path expressions如'owner.address.street'。可以使用ReportQuery#setC
olumns(String[] columns)来定义属性。注意:这里的columns不是数据库中的columns
,column的名字应该和查询中的属性名一样。
下面的ReportQuery总结了每个ProductGroup的库存文章数目和价格:
Criteria crit = new Criteria();
Collection results = new Vector();
ReportQueryByCriteria q = QueryFactory.newReportQuery(
ProductGroup.class, crit);
// define the 'columns' of the report
q.setColumns(new String[] { "groupName",
"sum(allArticlesInGroup.stock)",
"sum(allArticlesInGroup.price)" });
crit.addGroupBy("groupName");
Iterator iter = broker.getReportQueryIteratorByQuery(q);