|
|
|
Brian Guan
|
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
|
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
|
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
|
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
|
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 |
||||||||||||||||
| Free Embeddable Forum Powered by Nabble | Help |