Grails CriteriaBuilder 添加限制

Grails CriteriaBuilder add Restrictions

我想创建我的条件对象并根据其他一些属性添加一些限制。

我试过类似的东西...

    long from, to;
    use(TimeCategory) {
        from = (1.month.ago).getTime() / 1000L
        to = (new Date()).getTime() / 1000L
    }

    def crit = Map.createCriteria()       

    // set date range
    crit.between("appear", from, to)

    // if testParam1 is present
    if (params.testParam1 && !(params.testParam1.equals("all") || params.testParam1.isEmpty())) {
        crit.eq("test1", testParam1)
    }

    // if testParam2 is present
    if (params.testParam2 && !(params.testParam2.equals("all") || params.testParam2.isEmpty())) {
        crit.eq("test2", testParam2)
    }

但每次我得到 java.lang.IllegalArgumentException

此异常来自 HibernateCriteriaBuilder class,其中 validateSimpleExpression 测试失败

/**
 * Creates a "between" Criterion based on the property name and specified lo and hi values
 * @param propertyName The property name
 * @param lo The low value
 * @param hi The high value
 * @return A Criterion instance
 */
public Object between(String propertyName, Object lo, Object hi) {
    if(!validateSimpleExpression()) {
        throwRuntimeException( new IllegalArgumentException("Call to [between] with propertyName ["+propertyName+"]  not allowed here."));
    }
    propertyName = calculatePropertyName(propertyName);
    return addToCriteria(Restrictions.between(propertyName, lo, hi));
}


private boolean validateSimpleExpression() {
    if(this.criteria == null) {
        return false;
    }
    return true;
}

知道如何动态添加一些限制吗?

你必须使用 Closure 并在 criteria 中传递它,让我举个简单的例子:

def criteria = Map.createCriteria()   


Closure closure = {builder ->
   if(params.testParam1){
       builder.eq("test1", testParam1)
   }
   if(params.testParam2){
       builder.eq("test2", testParam2)
   }
   builder.beetwen("appear", from, to)
}

比:

 def result = criteria.list(){
    closure(criteria)        
 }

@RomanRomanovsky 的答案的替代方法是传递 Closure,然后将 HibernateCriteriaBuilder 的委托分配给添加的闭包的 delegate:

def additionalRestrictions = {
   if(params.testParam1){
       eq("test1", testParam1)
   }
   ...
}

// usage
def result = criteria.list(){
    additionalRestrictions.delegate = delegate
    additionalRestrictions()       
}

@RomanRomanovsky 的方式对我来说实际上是新的,我想我更喜欢它。需要注意的一件事是,使用 delegate 不需要任何前缀到闭包中的方法(eq、createAlias 等)。

谢谢两位的建议。它引导我走向正确的方向。这是我的最终方法

long from, to;
use(TimeCategory) {
    from = (1.month.ago).getTime() / 1000L
    to = (new Date()).getTime() / 1000L
}

def records = Map.withCriteria {       

    // set date range
    between("appear", from, to)

    // if testParam1 is present
    if (params.testParam1 && !(params.testParam1.equals("all") || params.testParam1.isEmpty())) {
        eq("test1", testParam1)
    }

    // if testParam2 is present
    if (params.testParam2 && !(params.testParam2.equals("all") || params.testParam2.isEmpty())) {
        eq("test2", testParam2)
    }

}

总是可以使用 Hibernate 条件查询

    Criteria criteria = sessionFactory.currentSession.createCriteria(Map.class)
        .add(Restrictions.between('appear', from, to))

    // if testParam1 is present
    if (params.testParam1 && !(params.testParam1.equals("all") || params.testParam1.isEmpty())) {
        criteria.add(Restrictions.eq("test1", testParam1))
    }

我最终这样做是为了允许一个函数 return 一个标准,在使用之前由调用者扩充。