-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 
Author Message
 Post subject: Example and association class
PostPosted: Wed May 25, 2005 3:08 am 
Regular
Regular

Joined: Tue Jan 27, 2004 12:22 pm
Posts: 103
Hi,

I created an slightly different Example class which also allows you to set checking on associated objects. I thought this would be helpful because it can be done in a single query.

The essential differences are:
Code:
  private boolean isAllowingAssociationId;
   
   public Example enableAssociations(){
   isAllowingAssociationId=true;
   return this;
   }
   public static AssociationExample getInstance(Object entity){
       if (entity==null) throw new NullPointerException("null example");
      return new AssociationExample(entity, NOT_NULL);
   }
   private boolean isPropertyIncluded(Object value, String name, Type type) {
      return !excludedProperties.contains(name) &&
         (type.isAssociationType() && isAllowingAssociationId)  &&
         selector.include(value, name, type);
   }
   


The complete class AssociationExample
Code:
public class AssociationExample extends Example {
    private static final Log log = LogFactory.getLog(AssociationExample.class);
   private final Set excludedProperties = new HashSet();
   private PropertySelector selector;
   private final Object entity;
   private MatchMode matchMode;
   
   protected static final PropertySelector NOT_NULL = new NotNullPropertySelector();
   protected static final PropertySelector ALL = new AllPropertySelector();
   protected static final PropertySelector NOT_NULL_OR_ZERO = new NotNullOrZeroPropertySelector();
    private boolean isLikeEnabled;
    private boolean isIgnoreCaseEnabled;
    private boolean isAllowingAssociationId;

   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 Example setPropertySelector(PropertySelector selector) {
       super.setPropertySelector(selector);
      this.selector = selector;
      return this;
   }
   
   public Example enableAssociations(){
       isAllowingAssociationId=true;
       return this;
   }
   
   /**
    * Exclude zero-valued properties
    */
   public Example excludeZeroes() {
       super.excludeZeroes();
      setPropertySelector(NOT_NULL_OR_ZERO);
      return this;
   }

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

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

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

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

   /**
    * Exclude a particular named property
    */
   public Example excludeProperty(String name) {
       super.excludeProperty(name);
      excludedProperties.add(name);
      return this;
   }
   
    public static Example create(Object entity){
        if (entity==null) throw new NullPointerException("null example");
      return new AssociationExample(entity, NOT_NULL);
    }
   
    public static AssociationExample getInstance(Object entity){
        if (entity==null) throw new NullPointerException("null example");
      return new AssociationExample(entity, NOT_NULL);
    }
    /**
     * @see org.hibernate.criterion.Example
     * @param entity
     * @param selector
     */
    public AssociationExample(Object entity, PropertySelector selector) {
      super(entity,selector);
      this.entity=entity;
      this.selector=selector;
    }

   
   private boolean isPropertyIncluded(Object value, String name, Type type) {
      return !excludedProperties.contains(name) &&
         (type.isAssociationType() && isAllowingAssociationId)  &&
         selector.include(value, name, type);
   }

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


It would be nice if this can be included in the Example class. [/b]

_________________
Dencel
- The sun has never seen a shadow -


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 26, 2005 7:08 am 
Regular
Regular

Joined: Tue Jan 27, 2004 12:22 pm
Posts: 103
Sorry but:
Code:
private boolean isPropertyIncluded(Object value, String name, Type type) {
      return !excludedProperties.contains(name) &&
         (type.isAssociationType() && isAllowingAssociationId)  &&
         selector.include(value, name, type);
   }


Should be:
Code:
private boolean isPropertyIncluded(Object value, String name, Type type) {
      return !excludedProperties.contains(name) &&
         (!type.isAssociationType() || isAllowingAssociationId)  &&
         selector.include(value, name, type);
   }

_________________
Dencel
- The sun has never seen a shadow -


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 25, 2005 12:02 pm 
Newbie

Joined: Mon Apr 04, 2005 5:31 am
Posts: 3
Hi,

Chapter 16.6 Example queries
...identifiers and associations are ignored !!!

Somebody knows the reason ?

Thanks for any advice.


Top
 Profile  
 
 Post subject: Re: Example and association class
PostPosted: Fri Oct 28, 2005 2:27 pm 
Beginner
Beginner

Joined: Fri Apr 15, 2005 3:08 pm
Posts: 26
Dencel wrote:
I created an slightly different Example class which also allows you to set checking on associated objects. I thought this would be helpful because it can be done in a single query.

It would be nice if this can be included in the Example class.


Dencel, thanks for the idea. I too would like to see this capability added to the Example class.

As currently implemented, QBE is quite powerful. However, in our app, we have numerous search screens where the user can search for an entity based on not only the entity's non-association properties (e.g. some String value) but also the entity's foreign keys. It would be nice if Example could automatically handle these foreign key associations instead of having to manually call createCriteria(associationPath). I find createCriteria is particularly inconvenient if you have to search on more than one association at a time because the Criteria returned by the method is "rooted" at the associated entity, not the original entity.

If anyone wants to use Dencel's class, which extends Example, it won't compile as-is (at least it didn't work for me). The main problem is that the key method you have to override, isPropertyIncluded, is private in Example. I also tried to encapsulate an Example instance in another class but again I couldn't get it to work because of accessability issues with some methods.

So, I ended up just making a copy of Example and modified the code as needed. I put my copy in a different package which caused a couple of accessiblity issues due to some dependent classes and their methods being declared only package accessible. For example, the NullExpression() constructor is package accessable. I got around that by changing this line of code:
Code:
crit = new NullExpression(propertyName);

to this:
Code:
crit = Expression.isNull(propertyName);


Another problem is that MatchMode.toMatchString() is again only package accessable. A got around that by copying the MatchMode class into the same package as my Example class. Kludgy, but it works. :-)

Like Dencel, I added a new boolean instance variable to indicate whether or not to include associations. I called my variable includeAssociations instead of isAllowingAssociationId.

The key method is isPropertyIncluded. Here's my implementation:
Code:
  private boolean isPropertyIncluded(Object value, String name, Type type) {
    return
      !excludedProperties.contains(name) &&
      selector.include(value, name, type) &&
      (!type.isAssociationType() ||
        (type.isAssociationType() &&
          includeAssociations &&
          !type.isPersistentCollectionType()));
  }


Note that my implementation is slightly different than Dencel's. I do not include associations that are PersistentCollectionType (i.e. one-to-many); I only include assocations that either many-to-one or one-to-one. To me, it just didn't make sense to include one-to-many associations because I only wanted to search for foreign keys. Call me crazy. If I wasn't so lazy, I probably would have added another boolean to turn one-to-many associations on/off.

Anyway, my solution seems to work. If anyone would like my full class posted please let me know.

BTW, another thing I don't like about Example is that in addition to ignoring associations, it also ignores identifiers. I know the workaround is easy but, IMHO, it should be handled automatically instead of me having to manually code "if identifier in Example is not null then do a load/get instead" everytime I want to use QBE. If this capability is added in the future, it should come with a flag to allow the user of the Example class to turn it on/off.


Top
 Profile  
 
 Post subject: Re: Example and association class
PostPosted: Wed Nov 16, 2005 8:20 pm 
Beginner
Beginner

Joined: Fri Apr 15, 2005 3:08 pm
Posts: 26
Initially I made my AssociationExample class for use with Hibernate 2. Today I tried using it for Hibernate 3. However, due to Hibernate 3's extensive refactoring of the criterion API, I had to make a new AssociationExample class. Fortunately, in Hibernate 3, MatchMode.toMatchString() is now public so I didn't have to make a copy of the MatchMode class. :-)

Below is the full AssociationExample class for Hibernate 3. There are only a few minor differences between my AssociationExample class and Hibernate 3's (3.0.5 to be exact) Example class. If you want to see the differences, I leave it as an exercise to the reader to get out their favourite diff tool.

I hope this class is helpful to someone besides me. Note, however, because I have made a copy of Example's code as opposed to deriving from it (reasons are given in my previous message), you use it at your own risk! If Example's implementation changes, you probably will have to change AssociationExample. You have been warned!

Code:
package com.mycompanyname.core.hibernate3;

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.
* @author original code by Gavin King, modified by jkelly
* @see <a href="http://forum.hibernate.org/viewtopic.php?t=942872">Example and
* 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;
  }
}


Top
 Profile  
 
 Post subject: Example and association class
PostPosted: Sat Apr 15, 2006 2:25 pm 
Newbie

Joined: Fri Apr 14, 2006 1:04 am
Posts: 6
Has this issue been addressed?

It seems intuitive that QBE would work with Examples being based on properties that involve associations with other classes.

What is the explanation for this design decision?

Thanks.

Josh.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 10, 2007 3:55 pm 
Newbie

Joined: Wed Apr 11, 2007 2:11 pm
Posts: 10
thanks for your workaround it works really well


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 12, 2007 7:19 am 
Newbie

Joined: Wed Dec 13, 2006 8:18 am
Posts: 3
I tried to use this Class to query for Data, but i only get:

"object references an unsaved transient instance - save the transient instance before flushing"

:-(


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 28, 2007 1:35 pm 
Newbie

Joined: Mon Mar 05, 2007 9:04 am
Posts: 6
Location: Belarus
cyboc, I feel I have to buy you a beer :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 23, 2007 8:46 am 
Newbie

Joined: Tue Oct 23, 2007 8:38 am
Posts: 2
cyboc , your code is great!
Exactly what I need..
However, your class does not support composite-id.
Here is my code:
[code]
package it.asc.aud.reports.business;

import java.util.ArrayList;
import java.util.Arrays;
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.
* @author original code by Gavin King, modified by jkelly
* @see <a href="http://forum.hibernate.org/viewtopic.php?t=942872">Example and
* 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) );
List propertyNames = new ArrayList();
propertyNames.addAll(Arrays.asList(meta.getPropertyNames()));


List propertyTypes = new ArrayList();
propertyTypes.addAll(Arrays.asList(meta.getPropertyTypes()));

//TODO: get all properties, not just the fetched ones!
List propertyValues = new ArrayList();
propertyValues.addAll(Arrays.asList(meta.getPropertyValues( entity, getEntityMode(criteria, criteriaQuery) )));
if (meta.getIdentifierPropertyName()!=null)
{
propertyNames.add(meta.getIdentifierPropertyName());
propertyTypes.add(meta.getIdentifierType());
propertyValues.add(meta.getIdentifier(entity, getEntityMode(criteria, criteriaQuery) ));
}

for (int i=0; i<propertyNames.size(); i++) {
Object propertyValue = propertyValues.get(i);
String propertyName = (String) propertyNames.get(i);

boolean isPropertyIncluded = i!=meta.getVersionProperty() &&
isPropertyIncluded( propertyValue, propertyName, (Type) propertyTypes.get(i) );
if (isPropertyIncluded) {
if ( ((Type) propertyTypes.get(i)).isComponentType() ) {
appendComponentCondition(
propertyName,
propertyValue,
(AbstractComponentType) propertyTypes.get(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) );

List propertyNames = new ArrayList();
propertyNames.addAll(Arrays.asList(meta.getPropertyNames()));


List propertyTypes = new ArrayList();
propertyTypes.addAll(Arrays.asList(meta.getPropertyTypes()));

//TODO: get all properties, not just the fetched ones!
List values = new ArrayList();
values.addAll(Arrays.asList(meta.getPropertyValues( entity, getEntityMode(criteria, criteriaQuery) )));
if (meta.getIdentifierPropertyName()!=null)
{
propertyNames.add(meta.getIdentifierPropertyName());
propertyTypes.add(meta.getIdentifierType());
values.add(meta.getIdentifier(entity, getEntityMode(criteria, criteriaQuery) ));
}
List list = new ArrayList();
for (int i=0; i<propertyNames.size(); i++) {
Object value = values.get(i);
Type type = (Type) propertyTypes.get(i);
String name = (String) propertyNames.get(i);

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

if (isPropertyIncluded) {
if ( ((Type) propertyTypes.get(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]


Top
 Profile  
 
 Post subject: Re:
PostPosted: Sun Jul 11, 2010 10:46 pm 
Newbie

Joined: Sun Jul 11, 2010 10:36 pm
Posts: 1
michael.mest wrote:
I tried to use this Class to query for Data, but i only get:

"object references an unsaved transient instance - save the transient instance before flushing"

:-(

I met the same problem when I post an example with my sub example not persisted(the identify is null) , who can tell me how to solve this?


Top
 Profile  
 
 Post subject: Re: Example and association class
PostPosted: Mon Jul 12, 2010 3:39 am 
Newbie

Joined: Tue Oct 23, 2007 8:38 am
Posts: 2
I'm sorry.
This is a problem since (about) version 3.2 and I think it's an hibernate issue.
I can't understand why hibernate checks unsaved transient instance during a query, even in a read-only transaction.
Obviously your entity cannot have an id, because it is used as example


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.