Grails hack之改写findAll和find方法

Grails hack之改写findAll和find方法,第1张

概述GORM的查询方法很方便(可查看http://www.grails.org/doc/1.2.x/ref/Domain%20Classes/findAll.html)   但因为我现在用Db4o,根本就不需要ORM,GORM的finders派不上用场。但是GORM把finders以及validate注入到Domain Classes中的方式对我们很有启发性。   Db4o提供三种查询方式:QBE,

GORM的查询方法很方便(可查看http://www.grails.org/doc/1.2.x/ref/Domain%20Classes/findAll.HTML)

 

但因为我现在用Db4o,根本就不需要ORM,GORM的finders派不上用场。但是GORM把finders以及valIDate注入到Domain Classes中的方式对我们很有启发性。

 

Db4o提供三种查询方式:QBE, NQ和SODA。其中NQ是type-safe的,在编译期可以作语法检查,在运行期可以被Db4o转化成高效的SODA。我不喜欢在Grails中使用NQ,一是因为这让代码看起来不太漂亮,二是无法保证所有的NQ都会被转化成SODA。

 

利用Groovy的Closure我写了两个方法:findAll和find,最终执行的都是SODA查询。改一改Grails的FindAllPersistentMethod代码:

 

package com.grs.db4opersistence.Metaclass;import com.db4o.ObjectContainer;import com.db4o.query.query;import com.grs.utils.GroovyDataUtils;import groovy.lang.MissingMethodException;import groovy.lang.Closure;import org.springframework.beans.SimpleTypeConverter;import java.util.Iterator;import java.util.Map;import java.util.regex.Pattern;/** * The "findAll" persistent static method allows searching for instances * * Usages: * (1) 0 arguments: User.findAll() * (2) 1 argument : User.findAll(sortInfoAndExampleMap) : User.findAll(sort:'dateCreated',order:'asc',department:department) * (3) 1 argument : User.findAll(exampleObject) * (4) 2 arguments: User.findAll(sortInfoMap,exampleObject)  : User.findAll([sort:'dateCreated',order:'asc'],userExample) * (5) 1 argument : User.findAll{it.descend('department').constrain(department)} * (6) 2 arguments: User.findAll(sort:'dateCreated',order:'asc'){it.descend('department').constrain(department)} * (7) 2 arguments: User.findAll(sort:'dateCreated',department:department){other complex constraints...} * (8) 3 arguments: User.findAll(sortInfoMap,exampleObject){other complex constraints} * * @author Sam Chen * * Created: Jun 2,2010 * */public class FindAllPersistentMethod extends AbstractStaticPersistentMethod {    public static SimpleTypeConverter converter = new SimpleTypeConverter();	public FindAllPersistentMethod(ObjectContainer objectContainer,ClassLoader classLoader) {		super(objectContainer,classLoader,Pattern.compile("^findAll$"));	}	protected Object doInvokeInternal(final Class clazz,String methodname,Closure additionalCriteria,final Object[] arguments) {		return doFindAll(clazz,methodname,additionalCriteria,arguments);	}    protected final Object doFindAll(final Class clazz,final Object[] arguments) {            if (arguments.length == 0) {                query q = getDb4oTemplate().query();                q.constrain(clazz);                q.descend("deleted").constrain(false);                return q.execute();            }            if (arguments.length == 1) {                Object arg = arguments[0];                if(clazz.isAssignableFrom(arg.getClass())) {                     return getDb4oTemplate().queryByExample(arg);                } else if(arg instanceof Map) {                    query q = getDb4oTemplate().query();                    q.constrain(clazz);q.descend("deleted").constrain(false);                    Map map = (Map) arg;                    if (map.containsKey("sort") && map.containsKey("order")) {                        if (map.get("order").equals("desc")) {                            q.descend((String)map.get("sort")).orderDescending();                        } else {                            q.descend((String)map.get("sort")).orderAscending();                        }                    }                    for(Iterator<String> it = map.keySet().iterator(); it.hasNext();) {                        String key = it.next();                        if("sort".equals(key) || "order".equals(key)) {                            continue;                        }                        q.descend(key).constrain(map.get(key));                    }                    return q.execute();                } else if(arg instanceof Closure) {                    query q = getDb4oTemplate().query();                    q.constrain(clazz);q.descend("deleted").constrain(false);                    ((Closure)arg).call(q);                    return q.execute();                } else {                    throw new MissingMethodException(methodname,clazz,arguments);                }            }            if (arguments.length == 2) {                Object arg0 = arguments[0];                Object arg1 = arguments[1];                if(!(arg0 instanceof Map)) {                    throw new MissingMethodException(methodname,arguments);                }                query q = getDb4oTemplate().query();                q.constrain(clazz);q.descend("deleted").constrain(false);                Map map = (Map) arg0;                if (map.containsKey("sort") && map.containsKey("order")) {                    if (map.get("order").equals("desc")) {                        q.descend((String)map.get("sort")).orderDescending();                    } else {                        q.descend((String)map.get("sort")).orderAscending();                    }                }                for (Iterator<String> it = map.keySet().iterator(); it.hasNext();) {                    String key = it.next();                    if("sort".equals(key) || "order".equals(key)) {                        continue;                    }                    q.descend(key).constrain(map.get(key));                }                if (arg1 instanceof Closure) {                    ((Closure) arg1).call(q);                } else if (arg1 instanceof Map || clazz.isAssignableFrom(arg1.getClass())) {                    // extract propertIEs from the domain object...                    applyConstraintsFromExample(arg1,q);                } else {                    throw new MissingMethodException(methodname,arguments);                }                return q.execute();            }            if (arguments.length == 3) {                Object arg0 = arguments[0]; // sortInfoMap                Object arg1 = arguments[1]; // example                Object arg2 = arguments[2]; // closure                if(!(arg0 instanceof Map) || !(arg1 instanceof Map || clazz.isAssignableFrom(arg1.getClass())) || !(arg2 instanceof Closure)) {                    throw new MissingMethodException(methodname,arguments);                }                query q = getDb4oTemplate().query();                q.constrain(clazz);q.descend("deleted").constrain(false);                Map map = (Map) arg0;                if (map.containsKey("sort") && map.containsKey("order")) {                    if (map.get("order").equals("desc")) {                        q.descend((String)map.get("sort")).orderDescending();                    } else {                        q.descend((String)map.get("sort")).orderAscending();                    }                }                // extract propertIEs from the domain object...                applyConstraintsFromExample(arg1,q);                ((Closure)arg2).call(q);                return q.execute();            }            throw new MissingMethodException(methodname,arguments);        }    private voID applyConstraintsFromExample(Object o,query q) {        Map propertIEs = (o instanceof Map ? (Map)o : GroovyDataUtils.getPropertIEs(o));        for(Iterator<String> it = propertIEs.keySet().iterator(); it.hasNext();) {            String key = it.next();            Object v = propertIEs.get(key);            if(v != null) {                q.descend(key).constrain(v);            }        }    }}

 

有了FindAllPersistentMethod方法,FindPersistentMethod就很简单了:

package com.grs.db4opersistence.Metaclass;import com.db4o.ObjectContainer;import com.db4o.ObjectSet;import groovy.lang.Closure;import org.springframework.beans.SimpleTypeConverter;import java.util.regex.Pattern;/** * <p> * The "find" persistent static method allows searching for an instance *  * @author Sam Chen * Created: Jun 2,2010 *  */public class FindPersistentMethod extends FindAllPersistentMethod {    public static SimpleTypeConverter converter = new SimpleTypeConverter();	public FindPersistentMethod(ObjectContainer objectContainer,classLoader);        this.setPattern(Pattern.compile("^find$"));	}	protected Object doInvokeInternal(final Class clazz,final Object[] arguments) {		ObjectSet os = (ObjectSet)this.doFindAll(clazz,arguments);        return os.size() > 0 ? os.get(0) : null;	}}
 

 

,同时修改它的method signature:

def findAllMethod = new FindAllPersistentMethod(objectContainer,application.classLoader)/** * Usages: * (1) 0 arguments: User.findAll() * (2) 1 argument : User.findAll(sortInfoAndExampleMap) : User.findAll(sort:'dateCreated',exampleObject){other complex constraints} */mc.static.findAll = {->    findAllMethod.invoke(mc.javaClass,"findAll",[] as Object[])}mc.static.findAll = {Object sortMapOrExampleOrClosure->    findAllMethod.invoke(mc.javaClass,[sortMapOrExampleOrClosure] as Object[])}mc.static.findAll = {Map map,Object eoc ->    findAllMethod.invoke(mc.javaClass,[map,eoc] as Object[])}mc.static.findAll = {Map map,Object example,Closure c->    findAllMethod.invoke(mc.javaClass,example,c] as Object[])}
 

再写一点测试代码:

package com.grs.sctmsimport grails.test.*class FindMethodIntegrationTests extends GrailsUnitTestCase {    protected voID setUp() {        super.setUp()        for (int i = 0; i < 100; i++) {          new User(username:"user#$i",password:"pwd").save()        }        new User(username:"[email protected]",password:"sam's password").save()    }    protected voID tearDown() {        super.tearDown()    }    voID testFindAllWithEmptyArgument() {        def users = User.findAll()        assertEquals 101,users.size()    }    voID testFindAllWithOneArguments() {//        def users = User.findAll(sort:'username',order:'asc')//        assertEquals '[email protected]',users[0].username        def users = User.findAll(sort:'username',password:'pwd')        assertEquals 100,users.size()        users = User.findAll(new User(password:'pwd'))        assertEquals 100,users.size()        users = User.findAll{it.descend('password').constrain('pwd')}        assertEquals 100,users.size()    }    voID testFindAllWithTwoArguments() {        def users = User.findAll([sort:'username',new User(password:'pwd'))        assertEquals 100,users.size()        users = User.findAll(sort:'username',order:'asc') {          it.descend('username').constrain('user#').like()        }        assertEquals 100,password:"sam's password") {          it.descend('username').constrain('[email protected]')        }        assertEquals 1,users.size()        assertEquals "[email protected]",users[0].username    }    voID testFindAllWithThreeArguments() {        def users = User.findAll([sort:'username',[password:"sam's password"]) {        }        assertEquals 1,users[0].username        users = User.findAll([sort:'username',new User(password:"sam's password")) {            it.descend('password').constrain("sam's password")        }        assertEquals 1,users[0].username    }}

 测试结果

-------------------------------------------------------Running 2 integration tests...Running test com.grs.sctms.FindMethodIntegrationTests...PASSEDRunning test com.grs.sctms.ValIDationIntegrationTests...PASSEDTests Completed in 2485ms ...-------------------------------------------------------Tests passed: 5Tests Failed: 0-------------------------------------------------------

不过有个小问题: 测试代码中被注释掉的部分

//        def users = User.findAll(sort:'username',users[0].username

通不过。每次跑的

users[0].username

的值都不一样 - 看来测试环境下排序没生效。而用grails run-app把它跑起来的时候,经deBUG证实数据是排好序的!怀疑是Grails的BUG...

总结

以上是内存溢出为你收集整理的Grails hack之改写findAll和find方法全部内容,希望文章能够帮你解决Grails hack之改写findAll和find方法所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1270363.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存