grails动态地将gorm子查询添加到现有查询中

grails动态地将gorm子查询添加到现有查询中,grails,groovy,gorm,detachedcriteria,Grails,Groovy,Gorm,Detachedcriteria,我希望有一个用于构建查询的util,这样我就可以为公共查询添加特定性,而不是一遍又一遍地硬编码类似的查询。 例如: DetachedCriteria query = DeviceConfiguration.where { ... } while(query.list(max: 2).size() > 1) QueryUtil.addConstraint(query, newConstraint) 但我在处理涉及多对多关系的查询时遇到了麻烦 如果我的域类是: class StringDes

我希望有一个用于构建查询的util,这样我就可以为公共查询添加特定性,而不是一遍又一遍地硬编码类似的查询。 例如:

DetachedCriteria query = DeviceConfiguration.where { ... }
while(query.list(max: 2).size() > 1) QueryUtil.addConstraint(query, newConstraint)
但我在处理涉及多对多关系的查询时遇到了麻烦

如果我的域类是:

class StringDescriptor {
    String name
    String stringValue
    static hasMany = [ deviceConfigurations: DeviceConfiguration ]
    static belongsTo = DeviceConfiguration
}

class DeviceConfiguration {
    Integer setting1
    Integer setting2
    static hasMany = [ stringDescriptors: StringDescriptor ]
}
我的设备配置如下所示:

DeviceConfiguration hondaAccord = new DeviceConfiguration(setting1: 1, setting2: 1)
DeviceConfiguration hondaCivic = new DeviceConfiguration(setting1: 2, setting2: 2)
DeviceConfiguration accord = new DeviceConfiguration(setting1: 3, setting2: 3)
StringDescriptor hondaDescriptor = new StringDescriptor(name: "make", stringValue: "honda")
StringDescriptor civicDescriptor = new StringDescriptor(name: "model", stringValue: "civic")
StringDescriptor accordDescriptor = new StringDescriptor(name: "model", stringValue: "accord")
hondaAccord.addToStringDescriptors(hondaDescriptor)
hondaAccord.addToStringDescriptors(accordDescriptor)
hondaCivic.addToStringDescriptors(hondaDescriptor)
hondaCivic.addToStringDescriptors(civicDescriptor)
accord.addToStringDescriptors(accordDescriptor)
hondaAccord.save(failOnError: true)
hondaCivic.save(failOnError: true)
accord.save(failOnError: true, flush: true)
//Lists hondaAccord and hondaCivic
DeviceConfiguration.byStringDescriptor("make", "honda").list()
//Lists hondaAccord and accord
DeviceConfiguration.byStringDescriptor("model", "accord").list()
// LISTS NOTHING... BUT WHYYYYY?
DeviceConfiguration.byStringDescriptor("make", "honda").byStringDescriptor("model", "accord").list()
我希望能够做到这一点:

def query = DeviceCollector.where{ stringDescriptors {name =~ "make" & stringValue =~ "honda"} }
if(query.list(max: 2)?.size() > 1)
    def query2 = query.where { stringDescriptors {name =~ "model" & stringValue =~ "civic"} }
if(query2.list(max: 2)?.size() > 1) 
    //...
但这不起作用-query2给出与第一个查询相同的结果。但当我这么做的时候,它工作得非常完美:

def query = DeviceCollector.where{ stringDescriptors {name =~ "make" & stringValue =~ "honda"} }
if(query.list(max: 2)?.size() > 1)
    def query2 = query.where { eq('setting1', 1) }
if(query.list(max: 2)?.size() > 1)
    def query3 = query.build { eq('setting2', 1) }
请告知:(

编辑感谢injecteer

现在我的域名包括:

class DeviceConfiguration {
    //...
    static namedQueries = {
        byStringDescriptor { String name, String value ->
            stringDescriptors {
                ilike 'name', name
                ilike 'stringValue', value
            }
        }
    }
}
我尝试将查询串在一起,如下所示:

DeviceConfiguration hondaAccord = new DeviceConfiguration(setting1: 1, setting2: 1)
DeviceConfiguration hondaCivic = new DeviceConfiguration(setting1: 2, setting2: 2)
DeviceConfiguration accord = new DeviceConfiguration(setting1: 3, setting2: 3)
StringDescriptor hondaDescriptor = new StringDescriptor(name: "make", stringValue: "honda")
StringDescriptor civicDescriptor = new StringDescriptor(name: "model", stringValue: "civic")
StringDescriptor accordDescriptor = new StringDescriptor(name: "model", stringValue: "accord")
hondaAccord.addToStringDescriptors(hondaDescriptor)
hondaAccord.addToStringDescriptors(accordDescriptor)
hondaCivic.addToStringDescriptors(hondaDescriptor)
hondaCivic.addToStringDescriptors(civicDescriptor)
accord.addToStringDescriptors(accordDescriptor)
hondaAccord.save(failOnError: true)
hondaCivic.save(failOnError: true)
accord.save(failOnError: true, flush: true)
//Lists hondaAccord and hondaCivic
DeviceConfiguration.byStringDescriptor("make", "honda").list()
//Lists hondaAccord and accord
DeviceConfiguration.byStringDescriptor("model", "accord").list()
// LISTS NOTHING... BUT WHYYYYY?
DeviceConfiguration.byStringDescriptor("make", "honda").byStringDescriptor("model", "accord").list()
我很困惑,又一次

由于injecteer的更新答案而进行编辑

耶,这是为我工作的命名查询:

class DeviceConfiguration {
    //...
    static namedQueries = {
        byStringDescriptor { List<StringDescriptor> descriptors ->
            sizeEq('stringDescriptors', descriptors.size())
            stringDescriptors {
                or {
                    for(descriptor in descriptors) {
                        and {
                            ilike 'name', descriptor.name
                            ilike 'stringValue', descriptor.stringValue
                        }
                    }
                }
            }

        }
    }
}

injecteer是我最喜欢的人。

使用
条件查询
命名查询
。它们都允许更好的链接

class DeviceConfiguration {

  static namedQueries = {

    byDescriptors { List vals -> 
      stringDescriptors { 
        or{
          for( def tuple in vals ){
            and{
              ilike 'name', "%${tuple[ 0 ]}%"
              ilike 'stringValue', "%${tuple[ 1 ]}%"
            }
          }
        }
      }
    }

  }       
}
所以你可以打电话:

DeviceConfiguration.byDescriptors( [ [ 'make', 'honda' ], [ 'model', 'accord' ] ] ).findAllBySetting1( 10 )
你应该知道什么连词是合适的

更新2

有这么多的
你什么都找不到

如果您启动一个类似
blah(honda,accord).list()
的查询,它将尝试查找带有
name='honda'和name='accord'
的StringDescriptor,这是不可能的,因此它不会返回任何结果

这就是为什么我倾向于认为,您的域模型根本不允许这样的查询——即使是在SQL级别

您的属性应清晰可辨,以便您可以通过本田(型号“make”)和雅阁(型号“model”)找到,它不应在“model”中查找“honda”


单个
设备配置
实例是否可以包含多个相同
类型的
StringDescriptor

谢谢!这对我来说绝对是正确的一步。但是我很难将我的用例的查询串在一起…我已经根据您的答案用我尝试过的方法更新了我的问题…有任何问题吗建议?非常感谢您迄今为止的帮助!很高兴知道您可以在命名查询中使用循环。但我似乎仍然无法获得我想要的行为。我已经用我尝试过的方法更新了我的问题…如果您还有其他建议,我将非常感谢:(在我的领域中,我将添加一个约束,防止任何单个设备配置指向同名的StringDescriptor…(例如,任何配置都不会指向
[名称:
make
,值:honda]
[名称:
make
,值:toyota]
)…所以我要做的是只查询引用了两个特定描述符的设备配置-
[name:make,value:honda]
[name:model,value:accord]
…啊,哦,我是个白痴。我现在明白了,谢谢你的帮助!我会更新我所做的,但基本上与你的答案相同。