先解释一下标题的含义:为了实现一个组合条件查询,先是使用HQL书写,然后改用Query by Criteria方式,再尝试Query by Example,最后自己实现了一个增强的Example类来解决问题。
关于此问题的起源请阅读我以前的一个帖子:http://www.iteye.com/post/523791。在该帖子中已经实现了从HQL到QBC的转变,在这里就不再重复了。
在上一个帖子中没有模型类Product及Category的代码,为了方便讨论补充如下:
Java代码
public class Category {
private Long id;
private String name; //类别名称
//Other code omitted
}
public class Product {
private Long id;
private String name; //商品名称
private Category category; //商品类别
private Date expDate; //有效期
private Float price; //单价
//Other code omitted
}
public class Category {
private Long id;
private String name; //类别名称
//Other code omitted
}
public class Product {
private Long id;
private String name; //商品名称
private Category category; //商品类别
private Date expDate; //有效期
private Float price; //单价
//Other code omitted
}
从前一个帖子中可以看到,使用QBC后代码有所减少,但还是得把构造查询条件的代码写死,这非常不爽。重读了《Java Persistence with Hibernate》一书,发觉QBE是个好东东,于是尝试用改造代码如下:
Java代码
public List<Product> getProducts(Product product) {
final Example exampleProduct =
Example.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
public List<Product> getProducts(Product product) {
final Example exampleProduct =
Example.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
代码非常简洁啊!我只要new一个Product实例,然后把要查询的条件值赋值到相应到属性上,如果某项条件未指定则相应的属性保留为默认的空值,将该实例传递给上面的getProducts方法,就能得到需要的结果了。超爽!
但是我却没办法把这段代码用在产品中,这是因为QBE有着严重的局限性:
1.不能查询指定在关联对象的属性上的条件。比如我想仅列出商品类别名称包括xyz的商品,代码如下:
Java代码
Category category = new Category();
category.setName("xyz");
Product product = new Product();
product.setCategory(category);
List<Product> products = getProducts(product);
Category category = new Category();
category.setName("xyz");
Product product = new Product();
product.setCategory(category);
List<Product> products = getProducts(product);
运行这段代码会列出所有的商品。
2.除了字符串条件可以调用enableLike()方法改用模糊查询外,其它数据类型的条件都只能等值比较。比如我无法查询所有有效的商品(有效期≥当前日期)。
难道就没有办法了吗?经过一番搜索,终于在Hibernate的官网论坛上找到一篇文章:http://forum.hibernate.org/viewtopic.php?t=942872。在该文章中,Dencel写了一个AssociationExample,经过大家的完善,终于解决了查询指定在关联对象的属性上的条件的问题。其主要的奥妙在于:
Java代码
//Hibernate的原版Example
//如果属性类型是关联的实体,则忽略
private boolean isPropertyIncluded(Object value, String name, Type type) {
return !excludedProperties.contains(name) &&
!type.isAssociationType() &&
selector.include(value, name, type);
}
//改版的AssociationExample
private boolean includeAssociations = true;
public boolean isIncludeAssociations()
{
return includeAssociations;
}
public void setIncludeAssociations(boolean includeAssociations)
{
this.includeAssociations = includeAssociations;
}
//如果属性类型是关联的实体,且该关联是一对一或多对一,且includeAssociations为true,则包括该属性
private boolean isPropertyIncluded(Object value, String name, Type type) {
return
!excludedProperties.contains(name) &&
selector.include(value, name, type) &&
(!type.isAssociationType() ||
(type.isAssociationType() &&
includeAssociations &&
!type.isCollectionType()));
}
//Hibernate的原版Example
//如果属性类型是关联的实体,则忽略
private boolean isPropertyIncluded(Object value, String name, Type type) {
return !excludedProperties.contains(name) &&
!type.isAssociationType() &&
selector.include(value, name, type);
}
//改版的AssociationExample
private boolean includeAssociations = true;
public boolean isIncludeAssociations()
{
return includeAssociations;
}
public void setIncludeAssociations(boolean includeAssociations)
{
this.includeAssociations = includeAssociations;
}
//如果属性类型是关联的实体,且该关联是一对一或多对一,且includeAssociations为true,则包括该属性
private boolean isPropertyIncluded(Object value, String name, Type type) {
return
!excludedProperties.contains(name) &&
selector.include(value, name, type) &&
(!type.isAssociationType() ||
(type.isAssociationType() &&
includeAssociations &&
!type.isCollectionType()));
}
解决了前面提到的第一个问题,第二个问题又怎么办呢?我想到一个办法:如果某个条件要使用其它的比较方式(比如大于等于),提供一个方法让用户为该属性指定比较方法,对于其它属性仍采用缺省的查询/比较方法:
Java代码
//Hibernate原版的Example
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
//增强后的EnhancedExample
private static final RestrictionHolder holder = new DefaultRestrictionHolder();
/**
* Restriction strategy definitions
*/
public static enum RestrictionStrategy {eq, ne, gt, lt, ge, le}
/**
* Restriction strategy holder for the query criteria
*/
public static interface RestrictionHolder {
/**
* Set a restriction strategy for a POJO's property
*/
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy);
/**
* Get the restriction strategy of the property
*/
public RestrictionStrategy get(String propertyName);
}
static final class DefaultRestrictionHolder implements RestrictionHolder {
private Map<String, RestrictionStrategy> strategies = new HashMap<String, RestrictionStrategy>();
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy) {
strategies.put(propertyName, strategy);
return this;
}
public RestrictionStrategy get(String propertyName) {
return strategies.get(propertyName);
}
}
/**
* Get the restriction strategy holder
*/
public RestrictionHolder getRestrictionHolder() {
return holder;
}
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果为该属性指定了比较条件,则使用指定的比较条件
RestrictionStrategy strategy = holder.get(propertyName);
if ( strategy != null ) {
switch(strategy) {
//case eq: crit = Restrictions.eq(propertyName, propertyValue);
case ne: crit = Restrictions.ne(propertyName, propertyValue); break;
case gt: crit = Restrictions.gt(propertyName, propertyValue); break;
case lt: crit = Restrictions.lt(propertyName, propertyValue); break;
case ge: crit = Restrictions.ge(propertyName, propertyValue); break;
case le: crit = Restrictions.le(propertyName, propertyValue); break;
default: crit = Restrictions.eq(propertyName, propertyValue);
};
}
else {
//否则使用默认的比较条件:如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
//Hibernate原版的Example
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
//增强后的EnhancedExample
private static final RestrictionHolder holder = new DefaultRestrictionHolder();
/**
* Restriction strategy definitions
*/
public static enum RestrictionStrategy {eq, ne, gt, lt, ge, le}
/**
* Restriction strategy holder for the query criteria
*/
public static interface RestrictionHolder {
/**
* Set a restriction strategy for a POJO's property
*/
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy);
/**
* Get the restriction strategy of the property
*/
public RestrictionStrategy get(String propertyName);
}
static final class DefaultRestrictionHolder implements RestrictionHolder {
private Map<String, RestrictionStrategy> strategies = new HashMap<String, RestrictionStrategy>();
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy) {
strategies.put(propertyName, strategy);
return this;
}
public RestrictionStrategy get(String propertyName) {
return strategies.get(propertyName);
}
}
/**
* Get the restriction strategy holder
*/
public RestrictionHolder getRestrictionHolder() {
return holder;
}
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果为该属性指定了比较条件,则使用指定的比较条件
RestrictionStrategy strategy = holder.get(propertyName);
if ( strategy != null ) {
switch(strategy) {
//case eq: crit = Restrictions.eq(propertyName, propertyValue);
case ne: crit = Restrictions.ne(propertyName, propertyValue); break;
case gt: crit = Restrictions.gt(propertyName, propertyValue); break;
case lt: crit = Restrictions.lt(propertyName, propertyValue); break;
case ge: crit = Restrictions.ge(propertyName, propertyValue); break;
case le: crit = Restrictions.le(propertyName, propertyValue); break;
default: crit = Restrictions.eq(propertyName, propertyValue);
};
}
else {
//否则使用默认的比较条件:如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
于是前面getProducts方法只需要简单修改一下:
Java代码
public List<Product> getProducts(Product product) {
//改用EnhancedExample来允许关联对象的条件查询
final EnhancedExample exampleProduct =
EnhancedExample.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
//指定expDate属性使用大于等于比较方法
exampleProduct.getRestrictionHolder().
set("expDate", EnhancedExample.RestrictionStrategy.ge);
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
public List<Product> getProducts(Product product) {
//改用EnhancedExample来允许关联对象的条件查询
final EnhancedExample exampleProduct =
EnhancedExample.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
//指定expDate属性使用大于等于比较方法
exampleProduct.getRestrictionHolder().
set("expDate", EnhancedExample.RestrictionStrategy.ge);
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
经过以上改进,QBE的实用性大大提高,能够真正解决较大多数的组合查询问题。
已知的问题:以上“增强的”QBE还无法解决范围查询(比如价格在0到1000之间),这是因为一个属性只能携带一个值(你不可能指定两个值给Product.price属性)。这种情况下需要修改getProducts方法,增加参数把价格范围传递进来,再以QBC方式把相应的条件加到crit变量上。范例代码就不再给出了。
完整的EnhancedExample源码请见附件。
EnhancedExample.zip (3 KB)
描述: 完整的EnhancedExample源码
下载次数: 219
关于此问题的起源请阅读我以前的一个帖子:http://www.iteye.com/post/523791。在该帖子中已经实现了从HQL到QBC的转变,在这里就不再重复了。
在上一个帖子中没有模型类Product及Category的代码,为了方便讨论补充如下:
Java代码
public class Category {
private Long id;
private String name; //类别名称
//Other code omitted
}
public class Product {
private Long id;
private String name; //商品名称
private Category category; //商品类别
private Date expDate; //有效期
private Float price; //单价
//Other code omitted
}
public class Category {
private Long id;
private String name; //类别名称
//Other code omitted
}
public class Product {
private Long id;
private String name; //商品名称
private Category category; //商品类别
private Date expDate; //有效期
private Float price; //单价
//Other code omitted
}
从前一个帖子中可以看到,使用QBC后代码有所减少,但还是得把构造查询条件的代码写死,这非常不爽。重读了《Java Persistence with Hibernate》一书,发觉QBE是个好东东,于是尝试用改造代码如下:
Java代码
public List<Product> getProducts(Product product) {
final Example exampleProduct =
Example.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
public List<Product> getProducts(Product product) {
final Example exampleProduct =
Example.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
代码非常简洁啊!我只要new一个Product实例,然后把要查询的条件值赋值到相应到属性上,如果某项条件未指定则相应的属性保留为默认的空值,将该实例传递给上面的getProducts方法,就能得到需要的结果了。超爽!
但是我却没办法把这段代码用在产品中,这是因为QBE有着严重的局限性:
1.不能查询指定在关联对象的属性上的条件。比如我想仅列出商品类别名称包括xyz的商品,代码如下:
Java代码
Category category = new Category();
category.setName("xyz");
Product product = new Product();
product.setCategory(category);
List<Product> products = getProducts(product);
Category category = new Category();
category.setName("xyz");
Product product = new Product();
product.setCategory(category);
List<Product> products = getProducts(product);
运行这段代码会列出所有的商品。
2.除了字符串条件可以调用enableLike()方法改用模糊查询外,其它数据类型的条件都只能等值比较。比如我无法查询所有有效的商品(有效期≥当前日期)。
难道就没有办法了吗?经过一番搜索,终于在Hibernate的官网论坛上找到一篇文章:http://forum.hibernate.org/viewtopic.php?t=942872。在该文章中,Dencel写了一个AssociationExample,经过大家的完善,终于解决了查询指定在关联对象的属性上的条件的问题。其主要的奥妙在于:
Java代码
//Hibernate的原版Example
//如果属性类型是关联的实体,则忽略
private boolean isPropertyIncluded(Object value, String name, Type type) {
return !excludedProperties.contains(name) &&
!type.isAssociationType() &&
selector.include(value, name, type);
}
//改版的AssociationExample
private boolean includeAssociations = true;
public boolean isIncludeAssociations()
{
return includeAssociations;
}
public void setIncludeAssociations(boolean includeAssociations)
{
this.includeAssociations = includeAssociations;
}
//如果属性类型是关联的实体,且该关联是一对一或多对一,且includeAssociations为true,则包括该属性
private boolean isPropertyIncluded(Object value, String name, Type type) {
return
!excludedProperties.contains(name) &&
selector.include(value, name, type) &&
(!type.isAssociationType() ||
(type.isAssociationType() &&
includeAssociations &&
!type.isCollectionType()));
}
//Hibernate的原版Example
//如果属性类型是关联的实体,则忽略
private boolean isPropertyIncluded(Object value, String name, Type type) {
return !excludedProperties.contains(name) &&
!type.isAssociationType() &&
selector.include(value, name, type);
}
//改版的AssociationExample
private boolean includeAssociations = true;
public boolean isIncludeAssociations()
{
return includeAssociations;
}
public void setIncludeAssociations(boolean includeAssociations)
{
this.includeAssociations = includeAssociations;
}
//如果属性类型是关联的实体,且该关联是一对一或多对一,且includeAssociations为true,则包括该属性
private boolean isPropertyIncluded(Object value, String name, Type type) {
return
!excludedProperties.contains(name) &&
selector.include(value, name, type) &&
(!type.isAssociationType() ||
(type.isAssociationType() &&
includeAssociations &&
!type.isCollectionType()));
}
解决了前面提到的第一个问题,第二个问题又怎么办呢?我想到一个办法:如果某个条件要使用其它的比较方式(比如大于等于),提供一个方法让用户为该属性指定比较方法,对于其它属性仍采用缺省的查询/比较方法:
Java代码
//Hibernate原版的Example
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
//增强后的EnhancedExample
private static final RestrictionHolder holder = new DefaultRestrictionHolder();
/**
* Restriction strategy definitions
*/
public static enum RestrictionStrategy {eq, ne, gt, lt, ge, le}
/**
* Restriction strategy holder for the query criteria
*/
public static interface RestrictionHolder {
/**
* Set a restriction strategy for a POJO's property
*/
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy);
/**
* Get the restriction strategy of the property
*/
public RestrictionStrategy get(String propertyName);
}
static final class DefaultRestrictionHolder implements RestrictionHolder {
private Map<String, RestrictionStrategy> strategies = new HashMap<String, RestrictionStrategy>();
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy) {
strategies.put(propertyName, strategy);
return this;
}
public RestrictionStrategy get(String propertyName) {
return strategies.get(propertyName);
}
}
/**
* Get the restriction strategy holder
*/
public RestrictionHolder getRestrictionHolder() {
return holder;
}
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果为该属性指定了比较条件,则使用指定的比较条件
RestrictionStrategy strategy = holder.get(propertyName);
if ( strategy != null ) {
switch(strategy) {
//case eq: crit = Restrictions.eq(propertyName, propertyValue);
case ne: crit = Restrictions.ne(propertyName, propertyValue); break;
case gt: crit = Restrictions.gt(propertyName, propertyValue); break;
case lt: crit = Restrictions.lt(propertyName, propertyValue); break;
case ge: crit = Restrictions.ge(propertyName, propertyValue); break;
case le: crit = Restrictions.le(propertyName, propertyValue); break;
default: crit = Restrictions.eq(propertyName, propertyValue);
};
}
else {
//否则使用默认的比较条件:如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
//Hibernate原版的Example
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
//增强后的EnhancedExample
private static final RestrictionHolder holder = new DefaultRestrictionHolder();
/**
* Restriction strategy definitions
*/
public static enum RestrictionStrategy {eq, ne, gt, lt, ge, le}
/**
* Restriction strategy holder for the query criteria
*/
public static interface RestrictionHolder {
/**
* Set a restriction strategy for a POJO's property
*/
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy);
/**
* Get the restriction strategy of the property
*/
public RestrictionStrategy get(String propertyName);
}
static final class DefaultRestrictionHolder implements RestrictionHolder {
private Map<String, RestrictionStrategy> strategies = new HashMap<String, RestrictionStrategy>();
public RestrictionHolder set(String propertyName, RestrictionStrategy strategy) {
strategies.put(propertyName, strategy);
return this;
}
public RestrictionStrategy get(String propertyName) {
return strategies.get(propertyName);
}
}
/**
* Get the restriction strategy holder
*/
public RestrictionHolder getRestrictionHolder() {
return holder;
}
protected void appendPropertyCondition(
String propertyName,
Object propertyValue,
Criteria criteria,
CriteriaQuery cq,
StringBuffer buf)
throws HibernateException {
Criterion crit;
if ( propertyValue!=null ) {
//当属性值不为空时,如果为该属性指定了比较条件,则使用指定的比较条件
RestrictionStrategy strategy = holder.get(propertyName);
if ( strategy != null ) {
switch(strategy) {
//case eq: crit = Restrictions.eq(propertyName, propertyValue);
case ne: crit = Restrictions.ne(propertyName, propertyValue); break;
case gt: crit = Restrictions.gt(propertyName, propertyValue); break;
case lt: crit = Restrictions.lt(propertyName, propertyValue); break;
case ge: crit = Restrictions.ge(propertyName, propertyValue); break;
case le: crit = Restrictions.le(propertyName, propertyValue); break;
default: crit = Restrictions.eq(propertyName, propertyValue);
};
}
else {
//否则使用默认的比较条件:如果是字符串且指定为模糊查询,则使用模糊查询,否则使用等值比较
boolean isString = propertyValue instanceof String;
SimpleExpression se = ( isLikeEnabled && isString ) ?
Restrictions.like(propertyName, propertyValue) :
Restrictions.eq(propertyName, propertyValue);
crit = ( isIgnoreCaseEnabled && isString ) ?
se.ignoreCase() : se;
}
}
else {
crit = Restrictions.isNull(propertyName);
}
String critCondition = crit.toSqlString(criteria, cq);
if ( buf.length()>1 && critCondition.trim().length()>0 ) buf.append(" and ");
buf.append(critCondition);
}
于是前面getProducts方法只需要简单修改一下:
Java代码
public List<Product> getProducts(Product product) {
//改用EnhancedExample来允许关联对象的条件查询
final EnhancedExample exampleProduct =
EnhancedExample.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
//指定expDate属性使用大于等于比较方法
exampleProduct.getRestrictionHolder().
set("expDate", EnhancedExample.RestrictionStrategy.ge);
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
public List<Product> getProducts(Product product) {
//改用EnhancedExample来允许关联对象的条件查询
final EnhancedExample exampleProduct =
EnhancedExample.create(product).
enableLike(MatchMode.ANYWHERE).
excludeZeroes();
//指定expDate属性使用大于等于比较方法
exampleProduct.getRestrictionHolder().
set("expDate", EnhancedExample.RestrictionStrategy.ge);
return (List<Product>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria crit =
session.createCriteria(Product.class).
add(exampleProduct);
return crit.list();
}
}
);
}
经过以上改进,QBE的实用性大大提高,能够真正解决较大多数的组合查询问题。
已知的问题:以上“增强的”QBE还无法解决范围查询(比如价格在0到1000之间),这是因为一个属性只能携带一个值(你不可能指定两个值给Product.price属性)。这种情况下需要修改getProducts方法,增加参数把价格范围传递进来,再以QBC方式把相应的条件加到crit变量上。范例代码就不再给出了。
完整的EnhancedExample源码请见附件。
EnhancedExample.zip (3 KB)
描述: 完整的EnhancedExample源码
下载次数: 219
相关推荐
1. Hibernate:Hibernate是一个开源的对象关系映射(ORM)框架,它允许开发者在Java应用中使用面向对象的方式来操作数据库。它通过提供一套API和元数据,将Java类与数据库表进行映射,从而简化了数据库操作。 2. ...
Query By Example(QBE)则是通过实例化一个对象,并设置其属性值,然后将这个对象作为查询的模板,Hibernate会根据对象的属性值生成对应的WHERE子句进行查询。这种方式在处理简单查询时非常直观,但当查询条件变得...
QBC是Hibernate提供的一个高级查询接口,它允许开发者通过实例化Criteria对象来构造查询条件,从而实现动态查询。QBC的优点在于它可以更好地映射到对象模型,避免了直接编写SQL语句,提高了代码的可读性和可维护性。...
3. **s2sh_relation22_QBE.zip**: QBE(Query By Example)是Hibernate的另一种查询方式,它允许根据一个对象实例来构建查询。这个压缩包可能包含了关于QBE的示例,帮助你理解如何基于对象实例进行查询。 通过学习...
2. 查询语言(HQL):Hibernate查询语言,类似于SQL,但面向对象,可以方便地进行复杂查询。 3. Criteria查询:提供动态构建查询的方式,无需预先编写HQL,更灵活。 4. Query By Example(QBE):根据给定对象实例的...
QBE是一种基于实例的查询方式,通过创建一个对象实例作为模板,然后根据该实例的属性进行匹配查询。例如,如果有一个`Student`类的对象`s`,其`giftortoy`字段为"2",那么通过`session.createCriteria(Student.class...
Hibernate 是一个开放源代码的 ORM(对象关系映射)框架,它为 Java 开发者提供了一种高效、高性能的方式将 Java 应用程序中的对象映射到数据库表中。在 Hibernate 中进行查询是其核心功能之一,本文将详细介绍 ...
首先,我们来看看Hibernate,这是一个流行的ORM(对象关系映射)框架,它简化了Java应用程序与数据库之间的交互。与传统的JDBC相比,Hibernate提供了一种对象封装的方式,使得开发者可以更专注于业务逻辑,而不是...
Criteria 查询机制主要包括 QBE(Query By Example)、QBC(Query By Criteria)和 HQL(Hibernate Query Language)三种方式。 QBE(Query By Example) QBE 是一种基于示例的查询机制,它可以根据一个示例对象来...
- **报表工具之JasperReports**:一个强大的报表生成工具,支持多种数据源并能够生成各种格式的报表。 - **使用Action返回数据生成Excel**:结合Struts2等框架实现将查询结果导出为Excel文件的功能。 - **Struts2 + ...
Hibernate 是一个开源的对象关系映射框架,它允许开发者将Java对象和关系数据库的数据进行映射,从而简化数据访问。以下是对Hibernate的一些关键知识点的详细解释: 1. **配置**: Hibernate 的配置通常通过`...
QBE允许通过一个实体示例来构建查询条件,从而获取与示例相匹配的对象集合。例如: ```java Cat exampleCat = new Cat(); exampleCat.setName("Tom"); List<Cat> cats = session.createCriteria(Cat.class) .add...
- **Hibernate**:是一个ORM(Object-Relational Mapping)框架,用于将Java对象与数据库表进行映射,简化数据库操作。 - **JPA(Java Persistence API)**:是Java标准的持久化API,提供了一套规范,而Hibernate...
在Java的持久化框架Hibernate中,Criteria API提供了一种动态构造SQL查询的方式,它允许开发者在运行时构建查询,而无需硬编码HQL(Hibernate Query Language)或原生SQL语句。Criteria API提供了丰富的功能,包括但...
QBE是通过提供一个对象实例作为模板来执行查询的方法。例如,在给定的代码片段中: ```java Student s = new Student(); s.setGiftOrToy("2"); Criteria cri = session.createCriteria(Student.class); cri.add...
- 实现树状结构是Hibernate中的一个高级主题,通常涉及到递归查询或使用特定的树结构算法。 #### HQL查询语言 - **Hibernate Query Language (HQL)** 是一种面向对象的查询语言,类似于SQL,但更加灵活和强大。 - *...
本文主要探讨Hibernate中的查询语言,包括面向对象的查询语言HQL,QueryBy Criteria (QBC),Query By Example (QBE),以及原生SQL的使用。 1. **大小写敏感性** HQL查询语句对Java类和属性名称的大小写敏感,而...