Grails 3如何使用detached criteria predicate传参构造criteria查询
实现方案
你写的示例没法直接生效的核心原因是:传入的闭包默认绑定的是定义位置的上下文,不是criteria查询的构建器对象,所以闭包里的eq这类查询方法找不到对应执行上下文,不会生效。只要手动处理闭包的委托规则,或者用GORM官方提供的可分离查询对象,就能实现你要的效果,完全不用在criteria块里堆大量if判断。
方案1:手动绑定闭包委托(最贴合你写的示例写法)
只需要在criteria块内把传入闭包的委托对象设置为当前criteria构建器,调整委托优先级即可,代码改动量极小:
// 你预期的调用方式完全不用改 def predicate = { eq 'field1', 1 } search(predicate) def search(Closure predicate) { return SampleClass.withCriteria() { // 绑定传入闭包的执行上下文到当前criteria构建器 predicate.delegate = delegate predicate.resolveStrategy = Closure.DELEGATE_FIRST predicate() // 执行传入的查询条件 eq 'field2', 2 // 注意:你原示例里这里重复写了eq 'field2',3,同字段同时等于两个值永远无结果,应为笔误 eq 'field3', 3 }.find() }
这种写法支持任意复杂度的条件闭包,你可以提前把不同业务场景的查询条件封装成独立闭包,按需传入即可。
方案2:使用GORM原生DetachedCriteria(更规范的可复用条件写法)
GORM本身提供了DetachedCriteria类专门做脱离具体查询实例的可复用条件定义,不需要手动处理闭包委托,适合跨多段业务逻辑复用查询条件的场景:
// 提前定义可复用的分离查询条件,不绑定具体查询会话 def detachedPredicate = new DetachedCriteria(SampleClass).build { eq 'field1', 1 } def search(DetachedCriteria predicate) { return predicate.withCriteria { eq 'field2', 2 eq 'field3', 3 }.find() } // 直接传入预定义的条件即可 search(detachedPredicate)
避免大量if判断的实践
把动态条件的判断逻辑从主criteria块里抽离,按业务场景封装成独立的条件构造闭包/DetachedCriteria实例即可,示例:
// 单独封装动态条件的判断逻辑,主查询里不用堆if def buildDynamicCondition(Long userId, String status, Date startTime) { return { if (userId != null) eq 'createUserId', userId if (status != null) eq 'orderStatus', status if (startTime != null) ge 'createTime', startTime } } // 主查询只保留固定通用逻辑 def queryOrderList(Closure dynamicCondition) { return Order.withCriteria { // 固定条件 eq 'isDeleted', false // 注入动态条件 dynamicCondition.delegate = delegate dynamicCondition.resolveStrategy = Closure.DELEGATE_FIRST dynamicCondition() // 固定排序 order 'createTime', 'desc' }.list() } // 按场景传参调用即可 def result = queryOrderList(buildDynamicCondition(1001, 'PAID', null))
注意事项
- 传入的条件闭包里如果要调用criteria的嵌套方法(比如
or、and、createAlias),两种方案都能正常支持,没有语法限制 - 如果只是单处使用的简单动态条件,用闭包传参更轻便;如果是全局复用的通用查询条件,优先用DetachedCriteria,稳定性更高
内容的提问来源于stack exchange,提问作者Victor Soares
相关产品推荐
相关产品推荐

