加强hibernate的criteria查询中的使用Example查询的

来源:互联网 发布:stm32烧录软件 编辑:程序博客网 时间:2024/05/21 10:46

        有人说Query更强大,但我人个比较喜欢用criteria,觉得使用criteria才符合Java开发的规范。

criteria在使用example进行关联的对象查询时,会得到非预期的结果。

举个例子:

两个简单实体Department:部门

以及另一个类Employee员工
这两个表的关联关系我就不多说了,这行都应该都懂,呵呵。。。

 

     此时,我需要通过一些特定的条件去查找employee,当然分页什么的就不说了,因为查询条件会根据客户需求不同而不同,所以直接使用Example进行操作
[code=java]
 Criteria criteria = getSession().createCriteria(Employee.class);
 if (empoyee != null) {
 criteria.add(Example.create(empoyee ));//这里会忽略关联
 }
 //.....中间是分页等处理
 List<?> result = criteria.list();
[/code]

注意上面的注释,Example进行查询是会忽略所有的null值以及关联的对象,故,如果我想根据empoyee 的department来查询empoyee 的话,就会将所有的empoyee 都查询出来,因为department被忽略了。

遇到这个问题有两种解决方法:

一、我的做法如下:

[code=java]
 Criteria criteria = getSession().createCriteria(Employee.class);
 if (empoyee != null) {
 criteria.add(Example.create(empoyee ));//这里会忽略关联

//加强后的Example查寻,不再忽略关联对象
criteria.createCriteria("dpartment").add(Restrictions.eq("id",empoyee .getDepartment.getId()));

}
 //.....中间是分页等处理
 List<?> result = criteria.list();
[/code]

二、下面是我在网上看到别人的做法,个人感觉有点麻烦:

(转)那么这个问题怎么解决呢,查看了Example类的源码后,我决定动手修改——当然不能直接去改它的源码,在参考了hibernate官方论坛后,新建了类:

[code=java]

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.SimpleExpression;
import org.hibernate.engine.TypedValue;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.AbstractComponentType;
import org.hibernate.type.Type;
import org.hibernate.util.StringHelper;

/**
* A copy of Hibernate's Example class, with modifications that allow you to
* include many-to-one and one-to-one associations in Query By Example (QBE)
* queries.
* association class </a>
*/
public class AssociationExample implements Criterion {

private final Object entity;
 private final Set excludedProperties = new HashSet();
 private PropertySelector selector;
 private boolean isLikeEnabled;
 private boolean isIgnoreCaseEnabled;
 private MatchMode matchMode;
 private boolean includeAssociations = true;

/**
 * A strategy for choosing property values for inclusion in the query
 * criteria
 */

public static interface PropertySelector {
 public boolean include(Object propertyValue, String propertyName, Type type);
 }

private static final PropertySelector NOT_NULL = new NotNullPropertySelector();
 private static final PropertySelector ALL = new AllPropertySelector();
 private static final PropertySelector NOT_NULL_OR_ZERO = new NotNullOrZeroPropertySelector();

static final class AllPropertySelector implements PropertySelector {
 public boolean include(Object object, String propertyName, Type type) {
 return true;
 }
 }

static final class NotNullPropertySelector implements PropertySelector {
 public boolean include(Object object, String propertyName, Type type) {
 return object!=null;
 }
 }

static final class NotNullOrZeroPropertySelector implements PropertySelector {
 public boolean include(Object object, String propertyName, Type type) {
 return object!=null && (
 !(object instanceof Number) || ( (Number) object ).longValue()!=0
 );
 }
 }

/**
 * Set the property selector
 */
 public AssociationExample setPropertySelector(PropertySelector selector) {
 this.selector = selector;
 return this;
 }

/**
 * Exclude zero-valued properties
 */
 public AssociationExample excludeZeroes() {
 setPropertySelector(NOT_NULL_OR_ZERO);
 return this;
 }

/**
 * Don't exclude null or zero-valued properties
 */
 public AssociationExample excludeNone() {
 setPropertySelector(ALL);
 return this;
 }

/**
 * Use the "like" operator for all string-valued properties
 */
 public AssociationExample enableLike(MatchMode matchMode) {
 isLikeEnabled = true;
 this.matchMode = matchMode;
 return this;
 }

/**
 * Use the "like" operator for all string-valued properties
 */
 public AssociationExample enableLike() {
 return enableLike(MatchMode.EXACT);
 }

/**
 * Ignore case for all string-valued properties
 */
 public AssociationExample ignoreCase() {
 isIgnoreCaseEnabled = true;
 return this;
 }

/**
 * Exclude a particular named property
 */
 public AssociationExample excludeProperty(String name) {
 excludedProperties.add(name);
 return this;
 }

/**
 * Create a new instance, which includes all non-null properties
 * by default
 * @param entity
 * @return a new instance of <tt>Example</tt>
 */
 public static AssociationExample create(Object entity) {
 if (entity==null) throw new NullPointerException("null AssociationExample");
 return new AssociationExample(entity, NOT_NULL);
 }

protected AssociationExample(Object entity, PropertySelector selector) {
 this.entity = entity;
 this.selector = selector;
 }

public String toString() {
 return "example (" + entity + ')';
 }

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()));
 }

public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
 throws HibernateException {

StringBuffer buf = new StringBuffer().append('(');
 EntityPersister meta = criteriaQuery.getFactory().getEntityPersister( criteriaQuery.getEntityName(criteria) );
 String[] propertyNames = meta.getPropertyNames();
 Type[] propertyTypes = meta.getPropertyTypes();
 //TODO: get all properties, not just the fetched ones!
 Object[] propertyValues = meta.getPropertyValues( entity, getEntityMode(criteria, criteriaQuery) );
 for (int i=0; i<propertyNames.length; i++) {
 Object propertyValue = propertyValues[i];
 String propertyName = propertyNames[i];

boolean isPropertyIncluded = i!=meta.getVersionProperty() &&
 isPropertyIncluded( propertyValue, propertyName, propertyTypes[i] );
 if (isPropertyIncluded) {
 if ( propertyTypes[i].isComponentType() ) {
 appendComponentCondition(
 propertyName,
 propertyValue,
 (AbstractComponentType) propertyTypes[i],
 criteria,
 criteriaQuery,
 buf
 );
 }
 else {
 appendPropertyCondition(
 propertyName,
 propertyValue,
 criteria,
 criteriaQuery,
 buf
 );
 }
 }
 }
 if ( buf.length()==1 ) buf.append("1=1"); //yuck!
 return buf.append(')').toString();
 }

private static final Object[] TYPED_VALUES = new TypedValue[0];

public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
 throws HibernateException {

EntityPersister meta = criteriaQuery.getFactory()
 .getEntityPersister( criteriaQuery.getEntityName(criteria) );
 String[] propertyNames = meta.getPropertyNames();
 Type[] propertyTypes = meta.getPropertyTypes();
 //TODO: get all properties, not just the fetched ones!
 Object[] values = meta.getPropertyValues( entity, getEntityMode(criteria, criteriaQuery) );
 List list = new ArrayList();
 for (int i=0; i<propertyNames.length; i++) {
 Object value = values[i];
 Type type = propertyTypes[i];
 String name = propertyNames[i];

boolean isPropertyIncluded = i!=meta.getVersionProperty() &&
 isPropertyIncluded(value, name, type);

if (isPropertyIncluded) {
 if ( propertyTypes[i].isComponentType() ) {
 addComponentTypedValues(name, value, (AbstractComponentType) type, list, criteria, criteriaQuery);
 }
 else {
 addPropertyTypedValue(value, type, list);
 }
 }
 }
 return (TypedValue[]) list.toArray(TYPED_VALUES);
 }

 private EntityMode getEntityMode(Criteria criteria, CriteriaQuery criteriaQuery) {
 EntityPersister meta = criteriaQuery.getFactory()
 .getEntityPersister( criteriaQuery.getEntityName(criteria) );
 EntityMode result = meta.guessEntityMode(entity);
 if (result==null) {
 throw new ClassCastException( entity.getClass().getName() );
 }
 return result;
 }

protected void addPropertyTypedValue(Object value, Type type, List list) {
 if ( value!=null ) {
 if ( value instanceof String ) {
 String string = (String) value;
 if (isIgnoreCaseEnabled) string = string.toLowerCase();
 if (isLikeEnabled) string = matchMode.toMatchString(string);
 value = string;
 }
 list.add( new TypedValue(type, value, null) );
 }
 }

protected void addComponentTypedValues(
 String path,
 Object component,
 AbstractComponentType type,
 List list,
 Criteria criteria,
 CriteriaQuery criteriaQuery)
 throws HibernateException {

if (component!=null) {
 String[] propertyNames = type.getPropertyNames();
 Type[] subtypes = type.getSubtypes();
 Object[] values = type.getPropertyValues( component, getEntityMode(criteria, criteriaQuery) );
 for (int i=0; i<propertyNames.length; i++) {
 Object value = values[i];
 Type subtype = subtypes[i];
 String subpath = StringHelper.qualify( path, propertyNames[i] );
 if ( isPropertyIncluded(value, subpath, subtype) ) {
 if ( subtype.isComponentType() ) {
 addComponentTypedValues(subpath, value, (AbstractComponentType) subtype, list, criteria, criteriaQuery);
 }
 else {
 addPropertyTypedValue(value, subtype, list);
 }
 }
 }
 }
 }

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);
 }

protected void appendComponentCondition(
 String path,
 Object component,
 AbstractComponentType type,
 Criteria criteria,
 CriteriaQuery criteriaQuery,
 StringBuffer buf)
 throws HibernateException {

if (component!=null) {
 String[] propertyNames = type.getPropertyNames();
 Object[] values = type.getPropertyValues( component, getEntityMode(criteria, criteriaQuery) );
 Type[] subtypes = type.getSubtypes();
 for (int i=0; i<propertyNames.length; i++) {
 String subpath = StringHelper.qualify( path, propertyNames[i] );
 Object value = values[i];
 if ( isPropertyIncluded( value, subpath, subtypes[i] ) ) {
 Type subtype = subtypes[i];
 if ( subtype.isComponentType() ) {
 appendComponentCondition(
 subpath,
 value,
 (AbstractComponentType) subtype,
 criteria,
 criteriaQuery,
 buf
 );
 }
 else {
 appendPropertyCondition(
 subpath,
 value,
 criteria,
 criteriaQuery,
 buf
 );
 }
 }
 }
 }
 }

 public boolean isIncludeAssociations()
 {
 return includeAssociations;
 }

 public void setIncludeAssociations(boolean includeAssociations)
 {
 this.includeAssociations = includeAssociations;
 }
}
[/code]

注意包名,之后,再使用Example的时候,就可以使用这个来实现查询中不忽略关联对象,修改后的代码:

[code=java]
 Criteria criteria = getSession().createCriteria(Reqmt.class);
 if (reqmt != null) {
 // criteria.add(Example.create(reqmt));//这里会忽略关联
 criteria.add(AssociationExample.create(reqmt));// 使用了自己建立的扩展example
 }
 // 分页处理。。。。
 List<?> result = criteria.list();
[/code]

原创粉丝点击