1. 程式人生 > >加強hibernate的criteria查詢中的使用Example查詢的

加強hibernate的criteria查詢中的使用Example查詢的

        有人說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]