Proposal for a Finder implementation in DAOs for AppFuse

5 messages Options
Embed this post
Permalink
Brian Guan

Proposal for a Finder implementation in DAOs for AppFuse

Reply Threaded More More options
Print post
Permalink
Hi all,

Just joined the list on Matt's suggestion...

I have an idea for a poor man's almost universal finder that looks like this:

New methods to UniversalDao and/or GenericDao

    /**
     * Generic method used to find all objects of a particular type
that satisfy the filter condition (ANDs) expressed as Map
     * @param clazz the type of objects (a.k.a. while table) to get data from
     * @param Map of String -> Object or Collection/array of Objects
     * @return List of populated objects
     */
    public List find(Class clazz, Map filter);

    /**
     * Generic method used to find all objects of a particular type
that satisfy one of the filter conditions expressed as List of Maps,
i.e. Disjunctive Normal Form ORs of ANDs
     * @param clazz the type of objects (a.k.a. while table) to get data from
     * @param List of Map of String -> Object or Collection/array of Objects
     * @return List of populated objects
     */
    public List find(Class clazz, List filters);


For example, to find all Members with First Name = "Brian", and Last
Name in ["Guan", "Yuan"] you call the find with:


 dao.find(Member.class,
         { "firstName" : "Brian" ,
           "lastName" : ["Guan", "Yuan"] })

The implementation can construct criteria or HQL/SQL that looks like

  select * from Member
  where firstName = 'Brian' and lastName in ('Guan', 'Yuan')


Other hacks/improvements can include special prefix/postfix to
column/property name like so:

 * "!firstName" : "Brian"   => NOT (firstName = 'Brian')
 * "firstName~" : "%rian%"  => (firstName like '%rian%')
 * "age>" : 30              => (age > 30)



Matt suggested that I look at the GenericDAO implementation and
dynamic finders from the "Don't repeat the DAO" article on IBM
DeveloperWorks?

  http://www-128.ibm.com/developerworks/java/library/j-genericdao.html


However, I don't particularly like the design in the IBM article.  It
relies on AOP and reflection on missing method to derive the query.  I
know this is how Rails and Grails implement their finders, but it
doesn't match a common usage of finders I always find myself doing...
i.e. Some advance Find form with user supplying possible values to
match on possible search fields.

For example, a Find Member form

  firstName: [   ]  hint: empty for all
   lastName: [   ]  hint: empty for all
        age: [ -ALL- ]
             [ 0 - 10]
             [11 - 20]
             [  >20  ]

If using the method mentioned in the article, my controller would need
to decide the method name of the finder in all possible combinations:

  dao.findByFirstName()
  dao.findByFirstNameAndLastName()
  dao.findByLastNameAndAgeRange()
  ...

With three possible search fields, I would need 2^3 = 8 combos!  What
if I have 8 fields to search on?  BTW, age range would require even
more magic.

I would much rather construct the find criteria using the design I was
proposing:

Map filter = new HashMap<String,Object>();

If (firstName != null && firstName.trim().length() > 0)
filter.put("firstName", firstName);

If (lastName != null && lastName.trim().length() > 0)
filter.put("lastName", lastName);

If (ageBeg != null)  filter.put("age>=", ageBeg);

If (ageEnd != null)  filter.put("age<=", ageEnd);


Then the call to dao is just:

  dao.find(Member.class, filter);

Or

  memberDao.find(filter);


What do you think?  I've used this pattern in the past and it cut down
on the number of finder methods I have to write tremendously.

- Brian Guan

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

hyuan

RE: Proposal for a Finder implementation in DAOs for AppFuse

Reply Threaded More More options
Print post
Permalink
Some javascript/style in this post has been disabled (why?)
I use this one. Seem it works. I know it requires hibernate and can only solve part of your problems , so just FYI.
 

public List<T> getObjects( final T constraint )

{

if ( constraint != null )

{

final Example example = Example.create( constraint )

.excludeZeroes();

return (List<T>) getHibernateTemplate().execute(

new HibernateCallback() {

public Object doInHibernate( Session session )

throws HibernateException

{

List result = session.createCriteria(

constraint.getClass() ).add( example )

.list();

return result;

}

} );

}

else

{

return getAll();

}

}





 


> Date: Fri, 27 Jul 2007 13:28:50 -0700

> From: [hidden email]
> To: [hidden email]
> Subject: [appfuse-dev] Proposal for a Finder implementation in DAOs for AppFuse
>
> Hi all,
>
> Just joined the list on Matt's suggestion...
>
> I have an idea for a poor man's almost universal finder that looks like this:
>
> New methods to UniversalDao and/or GenericDao
>
> /**
> * Generic method used to find all objects of a particular type
> that satisfy the filter condition (ANDs) expressed as Map
> * @param clazz the type of objects (a.k.a. while table) to get data from
> * @param Map of String -> Object or Collection/array of Objects
> * @return List of populated objects
> */
> public List find(Class clazz, Map filter);
>
> /**
> * Generic method used to find all objects of a particular type
> that satisfy one of the filter conditions expressed as List of Maps,
> i.e. Disjunctive Normal Form ORs of ANDs
> * @param clazz the type of objects (a.k.a. while table) to get data from
> * @param List of Map of String -> Object or Collection/array of Objects
> * @return List of populated objects
> */
> public List find(Class clazz, List filters);
>
>
> For example, to find all Members with First Name = "Brian", and Last
> Name in ["Guan", "Yuan"] you call the find with:
>
>
> dao.find(Member.class,
> { "firstName" : "Brian" ,
> "lastName" : ["Guan", "Yuan"] })
>
> The implementation can construct criteria or HQL/SQL that looks like
>
> select * from Member
> where firstName = 'Brian' and lastName in ('Guan', 'Yuan')
>
>
> Other hacks/improvements can include special prefix/postfix to
> column/property name like so:
>
> * "!firstName" : "Brian" => NOT (firstName = 'Brian')
> * "firstName~" : "%rian%" => (firstName like '%rian%')
> * "age>" : 30 => (age > 30)
>
>
>
> Matt suggested that I look at the GenericDAO implementation and
> dynamic finders from the "Don't repeat the DAO" article on IBM
> DeveloperWorks?
>
> http://www-128.ibm.com/developerworks/java/library/j-genericdao.html
>
>
> However, I don't particularly like the design in the IBM article. It
> relies on AOP and reflection on missing method to derive the query. I
> know this is how Rails and Grails implement their finders, but it
> doesn't match a common usage of finders I always find myself doing...
> i.e. Some advance Find form with user supplying possible values to
> match on possible search fields.
>
> For example, a Find Member form
>
> firstName: [ ] hint: empty for all
> lastName: [ ] hint: empty for all
> age: [ -ALL- ]
> [ 0 - 10]
> [11 - 20]
> [ >20 ]
>
> If using the method mentioned in the article, my controller would need
> to decide the method name of the finder in all possible combinations:
>
> dao.findByFirstName()
> dao.findByFirstNameAndLastName()
> dao.findByLastNameAndAgeRange()
> ...
>
> With three possible search fields, I would need 2^3 = 8 combos! What
> if I have 8 fields to search on? BTW, age range would require even
> more magic.
>
> I would much rather construct the find criteria using the design I was
> proposing:
>
> Map filter = new HashMap<String,Object>();
>
> If (firstName != null && firstName.trim().length() > 0)
> filter.put("firstName", firstName);
>
> If (lastName != null && lastName.trim().length() > 0)
> filter.put("lastName", lastName);
>
> If (ageBeg != null) filter.put("age>=", ageBeg);
>
> If (ageEnd != null) filter.put("age<=", ageEnd);
>
>
> Then the call to dao is just:
>
> dao.find(Member.class, filter);
>
> Or
>
> memberDao.find(filter);
>
>
> What do you think? I've used this pattern in the past and it cut down
> on the number of finder methods I have to write tremendously.
>
> - Brian Guan
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>



探索 Windows Vista 的世界 了解更多信息!
mraible

Re: Proposal for a Finder implementation in DAOs for AppFuse

Reply Threaded More More options
Print post
Permalink
In reply to this post by Brian Guan
Brian,

This seems like a good solution to me. I don't know how folks feel
about QBE (Query By Example) vs. using Maps, but I like the idea
behind making things simple.

The only issues I see are making it work for iBATIS as well. I don't
know how hard that will be. Regardless, I don't think we should limit
our Hibernate and JPA implementations just because it's not as easy to
do with iBATIS.

Thanks,

Matt

On 7/27/07, Brian Guan <[hidden email]> wrote:

> Hi all,
>
> Just joined the list on Matt's suggestion...
>
> I have an idea for a poor man's almost universal finder that looks like this:
>
> New methods to UniversalDao and/or GenericDao
>
>     /**
>      * Generic method used to find all objects of a particular type
> that satisfy the filter condition (ANDs) expressed as Map
>      * @param clazz the type of objects (a.k.a. while table) to get data from
>      * @param Map of String -> Object or Collection/array of Objects
>      * @return List of populated objects
>      */
>     public List find(Class clazz, Map filter);
>
>     /**
>      * Generic method used to find all objects of a particular type
> that satisfy one of the filter conditions expressed as List of Maps,
> i.e. Disjunctive Normal Form ORs of ANDs
>      * @param clazz the type of objects (a.k.a. while table) to get data from
>      * @param List of Map of String -> Object or Collection/array of Objects
>      * @return List of populated objects
>      */
>     public List find(Class clazz, List filters);
>
>
> For example, to find all Members with First Name = "Brian", and Last
> Name in ["Guan", "Yuan"] you call the find with:
>
>
>  dao.find(Member.class,
>          { "firstName" : "Brian" ,
>            "lastName" : ["Guan", "Yuan"] })
>
> The implementation can construct criteria or HQL/SQL that looks like
>
>   select * from Member
>   where firstName = 'Brian' and lastName in ('Guan', 'Yuan')
>
>
> Other hacks/improvements can include special prefix/postfix to
> column/property name like so:
>
>  * "!firstName" : "Brian"   => NOT (firstName = 'Brian')
>  * "firstName~" : "%rian%"  => (firstName like '%rian%')
>  * "age>" : 30              => (age > 30)
>
>
>
> Matt suggested that I look at the GenericDAO implementation and
> dynamic finders from the "Don't repeat the DAO" article on IBM
> DeveloperWorks?
>
>   http://www-128.ibm.com/developerworks/java/library/j-genericdao.html
>
>
> However, I don't particularly like the design in the IBM article.  It
> relies on AOP and reflection on missing method to derive the query.  I
> know this is how Rails and Grails implement their finders, but it
> doesn't match a common usage of finders I always find myself doing...
> i.e. Some advance Find form with user supplying possible values to
> match on possible search fields.
>
> For example, a Find Member form
>
>   firstName: [   ]  hint: empty for all
>    lastName: [   ]  hint: empty for all
>         age: [ -ALL- ]
>              [ 0 - 10]
>              [11 - 20]
>              [  >20  ]
>
> If using the method mentioned in the article, my controller would need
> to decide the method name of the finder in all possible combinations:
>
>   dao.findByFirstName()
>   dao.findByFirstNameAndLastName()
>   dao.findByLastNameAndAgeRange()
>   ...
>
> With three possible search fields, I would need 2^3 = 8 combos!  What
> if I have 8 fields to search on?  BTW, age range would require even
> more magic.
>
> I would much rather construct the find criteria using the design I was
> proposing:
>
> Map filter = new HashMap<String,Object>();
>
> If (firstName != null && firstName.trim().length() > 0)
> filter.put("firstName", firstName);
>
> If (lastName != null && lastName.trim().length() > 0)
> filter.put("lastName", lastName);
>
> If (ageBeg != null)  filter.put("age>=", ageBeg);
>
> If (ageEnd != null)  filter.put("age<=", ageEnd);
>
>
> Then the call to dao is just:
>
>   dao.find(Member.class, filter);
>
> Or
>
>   memberDao.find(filter);
>
>
> What do you think?  I've used this pattern in the past and it cut down
> on the number of finder methods I have to write tremendously.
>
> - Brian Guan
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>


--
http://raibledesigns.com

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Brian Guan

Re: Proposal for a Finder implementation in DAOs for AppFuse

Reply Threaded More More options
Print post
Permalink
Hi Matt and all,

Yes, my proposal looks like QBE but has a few pros:

 * using QBE, it is harder to differentiate between a condition that
property must be null vs property not even part of picture e.g.
  -- select from Foo where bar is null and id = 123
  -- select from Foo where id = 123

 * using QBE, it is harder to find by property in [list of possible values]

 * using QBE, it is harder to find by negative properties or wildcard text match

I guess to use QBE to achieve the above, one way is to pass to the finder:

 * is Null ignored or select flag
 * list of Examples to Accept
 * list of Examples to Reject


I think it is possible to extend this design for straight SQL, so I'd
imagine also possible for iBatis - but I don't know enough about it to
claim so.

Thanks for considering the proposal.

- Brian

On 8/9/07, Matt Raible <[hidden email]> wrote:

> Brian,
>
> This seems like a good solution to me. I don't know how folks feel
> about QBE (Query By Example) vs. using Maps, but I like the idea
> behind making things simple.
>
> The only issues I see are making it work for iBATIS as well. I don't
> know how hard that will be. Regardless, I don't think we should limit
> our Hibernate and JPA implementations just because it's not as easy to
> do with iBATIS.
>
> Thanks,
>
> Matt
>
> On 7/27/07, Brian Guan <[hidden email]> wrote:
> > Hi all,
> >
> > Just joined the list on Matt's suggestion...
> >
> > I have an idea for a poor man's almost universal finder that looks like this:
> >
> > New methods to UniversalDao and/or GenericDao
> >
> >     /**
> >      * Generic method used to find all objects of a particular type
> > that satisfy the filter condition (ANDs) expressed as Map
> >      * @param clazz the type of objects (a.k.a. while table) to get data from
> >      * @param Map of String -> Object or Collection/array of Objects
> >      * @return List of populated objects
> >      */
> >     public List find(Class clazz, Map filter);
> >
> >     /**
> >      * Generic method used to find all objects of a particular type
> > that satisfy one of the filter conditions expressed as List of Maps,
> > i.e. Disjunctive Normal Form ORs of ANDs
> >      * @param clazz the type of objects (a.k.a. while table) to get data from
> >      * @param List of Map of String -> Object or Collection/array of Objects
> >      * @return List of populated objects
> >      */
> >     public List find(Class clazz, List filters);
> >
> >
> > For example, to find all Members with First Name = "Brian", and Last
> > Name in ["Guan", "Yuan"] you call the find with:
> >
> >
> >  dao.find(Member.class,
> >          { "firstName" : "Brian" ,
> >            "lastName" : ["Guan", "Yuan"] })
> >
> > The implementation can construct criteria or HQL/SQL that looks like
> >
> >   select * from Member
> >   where firstName = 'Brian' and lastName in ('Guan', 'Yuan')
> >
> >
> > Other hacks/improvements can include special prefix/postfix to
> > column/property name like so:
> >
> >  * "!firstName" : "Brian"   => NOT (firstName = 'Brian')
> >  * "firstName~" : "%rian%"  => (firstName like '%rian%')
> >  * "age>" : 30              => (age > 30)
> >
> >
> >
> > Matt suggested that I look at the GenericDAO implementation and
> > dynamic finders from the "Don't repeat the DAO" article on IBM
> > DeveloperWorks?
> >
> >   http://www-128.ibm.com/developerworks/java/library/j-genericdao.html
> >
> >
> > However, I don't particularly like the design in the IBM article.  It
> > relies on AOP and reflection on missing method to derive the query.  I
> > know this is how Rails and Grails implement their finders, but it
> > doesn't match a common usage of finders I always find myself doing...
> > i.e. Some advance Find form with user supplying possible values to
> > match on possible search fields.
> >
> > For example, a Find Member form
> >
> >   firstName: [   ]  hint: empty for all
> >    lastName: [   ]  hint: empty for all
> >         age: [ -ALL- ]
> >              [ 0 - 10]
> >              [11 - 20]
> >              [  >20  ]
> >
> > If using the method mentioned in the article, my controller would need
> > to decide the method name of the finder in all possible combinations:
> >
> >   dao.findByFirstName()
> >   dao.findByFirstNameAndLastName()
> >   dao.findByLastNameAndAgeRange()
> >   ...
> >
> > With three possible search fields, I would need 2^3 = 8 combos!  What
> > if I have 8 fields to search on?  BTW, age range would require even
> > more magic.
> >
> > I would much rather construct the find criteria using the design I was
> > proposing:
> >
> > Map filter = new HashMap<String,Object>();
> >
> > If (firstName != null && firstName.trim().length() > 0)
> > filter.put("firstName", firstName);
> >
> > If (lastName != null && lastName.trim().length() > 0)
> > filter.put("lastName", lastName);
> >
> > If (ageBeg != null)  filter.put("age>=", ageBeg);
> >
> > If (ageEnd != null)  filter.put("age<=", ageEnd);
> >
> >
> > Then the call to dao is just:
> >
> >   dao.find(Member.class, filter);
> >
> > Or
> >
> >   memberDao.find(filter);
> >
> >
> > What do you think?  I've used this pattern in the past and it cut down
> > on the number of finder methods I have to write tremendously.
> >
> > - Brian Guan
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [hidden email]
> > For additional commands, e-mail: [hidden email]
> >
> >
>
>
> --
> http://raibledesigns.com
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

HelgeT

Re: Proposal for a Finder implementation in DAOs for AppFuse

Reply Threaded More More options
Print post
Permalink
In reply to this post by Brian Guan
Hi,

Here is my quick and dirty implementation of this concept based on Hibernate

Cheers, Helge

package com.org.dao;

import org.appfuse.dao.GenericDao;

import java.io.Serializable;
import java.util.List;
import java.util.Map;


/**
 * Author: Helge Tesgaard
 */
public interface NewGenericDao<T, PK extends Serializable> extends GenericDao<T, PK> {

  /**
   * Generic method used to find all objects of a particular type that satisfy the filter condition (ANDs) expressed as Map
   *
   * @param clazz   the type of objects (a.k.a. while table) to get data from
   * @param filter, Map of String -> Object or Collection/array of Objects
   * @return List of populated objects
   */
  public List<T> find(Class clazz, Map<String, List> filter, List<String> orderBy);

  /**
   * Generic method used to find all objects of a particular type that satisfy one of the filter conditions expressed as List of Maps, i.e. Disjunctive Normal Form ORs of ANDs
   *
   * @param clazz    the type of objects (a.k.a. while table) to get data from
   * @param filters, List of Map of String -> Object or Collection/array of Objects
   * @return List of populated objects
   */
  //public List find(Class clazz, List filters);


}

package com.org.dao.impl;

import com.org.dao.NewGenericDao;
import org.appfuse.dao.hibernate.GenericDaoHibernate;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Author: Helge Tesgaard
 */
public class NewGenericDaoHibernate<T, PK extends Serializable> extends GenericDaoHibernate<T, PK> implements NewGenericDao<T, PK> {
  /**
   * Constructor that takes in a class to see which type of entity to persist
   *
   * @param persistentClass the class type you'd like to persist
   * @see org.appfuse.dao.hibernate.GenericDaoHibernate
   */
  public NewGenericDaoHibernate(Class<T> persistentClass) {
    super(persistentClass);
  }


  public List<T> find(Class clazz, Map<String, List> filter, List<String> orderBy) {

    //http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Criteria.html
    Criteria crit = getHibernateTemplate().getSessionFactory().getCurrentSession().createCriteria(clazz);

    if(filter != null) {
      for(Iterator<String> iter = filter.keySet().iterator(); iter.hasNext();) {
        String key = iter.next();
        List value = filter.get(key);
        crit.add(Restrictions.in(key,value));        
      }
    }
    if(orderBy != null && orderBy.size() > 0) {
      for(Iterator<String> iter3 = orderBy.iterator(); iter3.hasNext();) {
          crit.addOrder(Order.asc(iter3.next()));
      }
    }
    String hqlStr = crit.toString();        

    return crit.list();
    //return getHibernateTemplate().find("from Customer as c where c.username = '"+userName+"' order by c.name");
    //return null;  //To change body of implemented methods use File | Settings | File Templates.
  }
}

package com.org.service;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * Author: Helge Tesgaard
 *
 * Generic Manager that talks to GenericDao to CRUD POJOs.
 *
 * <p>Extend this interface if you want typesafe (no casting necessary) managers
 * for your domain objects.
 *
 * @author Matt Raible
 * @param <T> a type variable
 * @param <PK> the primary key for that type
 */
public interface NewGenericManager<T, PK extends Serializable> {

    /**
     * Generic method used to get all objects of a particular type. This
     * is the same as lookup up all rows in a table.
     * @return List of populated objects
     */
    List<T> getAll();

    /**
     * http://www.nabble.com/Proposal-for-a-Finder-implementation-in-DAOs-for-AppFuse-t4159990s2369.html
     *
     * @param clazz
     * @param filter
     * @param orderBy
     * @return
     */
    public List<T> find(Class clazz, Map<String, List> filter, List<String> orderBy);

    /**
     * Generic method to get an object based on class and identifier. An
     * ObjectRetrievalFailureException Runtime Exception is thrown if
     * nothing is found.
     *
     * @param id the identifier (primary key) of the object to get
     * @return a populated object
     * @see org.springframework.orm.ObjectRetrievalFailureException
     */
    T get(PK id);

    /**
     * Checks for existence of an object of type T using the id arg.
     * @param id the identifier (primary key) of the object to get
     * @return - true if it exists, false if it doesn't
     */
    boolean exists(PK id);

    /**
     * Generic method to save an object - handles both update and insert.
     * @param object the object to save
     * @return the updated object
     */
    T save(T object);

    /**
     * Generic method to delete an object based on class and id
     * @param id the identifier (primary key) of the object to remove
     */
    void remove(PK id);

}

package com.org.service.impl;

import com.org.dao.NewGenericDao;
import com.org.service.NewGenericManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * Author: Helge Tesgaard
 * Date: 2007-09-26
 * Time: 00:26:20
 */
public class NewGenericManagerImpl<T, PK extends Serializable> implements NewGenericManager<T, PK> {
    /**
     * Log variable for all child classes. Uses LogFactory.getLog(getClass()) from Commons Logging
     */
    protected final Log log = LogFactory.getLog(getClass());

    /**
     * GenericDao instance, set by constructor of this class
     */
    protected NewGenericDao<T, PK> genericDao;

    /**
     * Public constructor for creating a new GenericManagerImpl.
     * @param genericDao the GenericDao to use for persistence
     */
    public NewGenericManagerImpl(final NewGenericDao<T, PK> genericDao) {
        this.genericDao = genericDao;
    }

    /**
     * {@inheritDoc}
     */
    public List<T> getAll() {
        return genericDao.getAll();
    }

    /**
     * {@inheritDoc}
     */
    public List<T> find(Class clazz, Map<String, List> filter, List<String> orderBy) {
        return genericDao.find(clazz, filter, orderBy);
    }

    /**
     * {@inheritDoc}
     */
    public T get(PK id) {
        return genericDao.get(id);
    }

    /**
     * {@inheritDoc}
     */
    public boolean exists(PK id) {
        return genericDao.exists(id);
    }

    /**
     * {@inheritDoc}
     */
    public T save(T object) {
        return genericDao.save(object);
    }

    /**
     * {@inheritDoc}
     */
    public void remove(PK id) {
        genericDao.remove(id);
    }
}

    <!--DataGroupManager-START-->
    <bean id="dataGroupManager" class="com.org.service.impl.NewGenericManagerImpl">
        <constructor-arg>
            <bean class="com.org.dao.impl.NewGenericDaoHibernate">
                <constructor-arg value="com.org.model.DataGroup"/>
                <property name="sessionFactory" ref="sessionFactory"/>
            </bean>
        </constructor-arg>
    </bean>
    <!--DataGroupManager-END-->
   

Example usage:
  public List getDataGroups() {    
    /*
    List values = new LinkedList();
    values.add("Shahid");
    Map filter = new HashMap<String, List<String>>();
    filter.put("name",values);
    */
    Map filter = new HashMap<String, List>();
    List<String> roles = getRoles();
    filter.put("authority", roles);


    return dataGroupManager.find(DataGroup.class, filter, null);
    //return sort(dataGroupManager.getAll());
  }







Brian Guan-3 wrote:
Hi all,

Just joined the list on Matt's suggestion...

I have an idea for a poor man's almost universal finder that looks like this:

New methods to UniversalDao and/or GenericDao

    /**
     * Generic method used to find all objects of a particular type
that satisfy the filter condition (ANDs) expressed as Map
     * @param clazz the type of objects (a.k.a. while table) to get data from
     * @param Map of String -> Object or Collection/array of Objects
     * @return List of populated objects
     */
    public List find(Class clazz, Map filter);

    /**
     * Generic method used to find all objects of a particular type
that satisfy one of the filter conditions expressed as List of Maps,
i.e. Disjunctive Normal Form ORs of ANDs
     * @param clazz the type of objects (a.k.a. while table) to get data from
     * @param List of Map of String -> Object or Collection/array of Objects
     * @return List of populated objects
     */
    public List find(Class clazz, List filters);


For example, to find all Members with First Name = "Brian", and Last
Name in ["Guan", "Yuan"] you call the find with:


 dao.find(Member.class,
         { "firstName" : "Brian" ,
           "lastName" : ["Guan", "Yuan"] })

The implementation can construct criteria or HQL/SQL that looks like

  select * from Member
  where firstName = 'Brian' and lastName in ('Guan', 'Yuan')


Other hacks/improvements can include special prefix/postfix to
column/property name like so:

 * "!firstName" : "Brian"   => NOT (firstName = 'Brian')
 * "firstName~" : "%rian%"  => (firstName like '%rian%')
 * "age>" : 30              => (age > 30)



Matt suggested that I look at the GenericDAO implementation and
dynamic finders from the "Don't repeat the DAO" article on IBM
DeveloperWorks?

  http://www-128.ibm.com/developerworks/java/library/j-genericdao.html


However, I don't particularly like the design in the IBM article.  It
relies on AOP and reflection on missing method to derive the query.  I
know this is how Rails and Grails implement their finders, but it
doesn't match a common usage of finders I always find myself doing...
i.e. Some advance Find form with user supplying possible values to
match on possible search fields.

For example, a Find Member form

  firstName: [   ]  hint: empty for all
   lastName: [   ]  hint: empty for all
        age: [ -ALL- ]
             [ 0 - 10]
             [11 - 20]
             [  >20  ]

If using the method mentioned in the article, my controller would need
to decide the method name of the finder in all possible combinations:

  dao.findByFirstName()
  dao.findByFirstNameAndLastName()
  dao.findByLastNameAndAgeRange()
  ...

With three possible search fields, I would need 2^3 = 8 combos!  What
if I have 8 fields to search on?  BTW, age range would require even
more magic.

I would much rather construct the find criteria using the design I was
proposing:

Map filter = new HashMap<String,Object>();

If (firstName != null && firstName.trim().length() > 0)
filter.put("firstName", firstName);

If (lastName != null && lastName.trim().length() > 0)
filter.put("lastName", lastName);

If (ageBeg != null)  filter.put("age>=", ageBeg);

If (ageEnd != null)  filter.put("age<=", ageEnd);


Then the call to dao is just:

  dao.find(Member.class, filter);

Or

  memberDao.find(filter);


What do you think?  I've used this pattern in the past and it cut down
on the number of finder methods I have to write tremendously.

- Brian Guan

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@appfuse.dev.java.net
For additional commands, e-mail: dev-help@appfuse.dev.java.net