【问题标题】:grails dynamically add gorm subquery to existing querygrails 将 gorm 子查询动态添加到现有查询中
【发布时间】:2014-10-08 14:45:05
【问题描述】:

我想要一个用于构建查询的实用程序,这样我就可以为常见查询添加特异性,而不是一遍又一遍地对类似的查询进行硬编码。 例如:

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)

我希望能够做到这一点:

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
            }
        }
    }
}

我尝试将查询串在一起看起来像这样:

//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
                        }
                    }
                }
            }

        }
    }
}

结果 (YAYYY) :) ...

StringDescriptor hondaDescriptor = new StringDescriptor(name: "make", stringValue: "honda")
StringDescriptor accordDescriptor = new StringDescriptor(name: "model", stringValue: "accord")

//returns nothing - **check**
def hondaQuery = DeviceConfiguration.byStringDescriptor([hondaDescriptor]).list()

//returns accord configuration - **check**
def accordQuery = DeviceConfiguration.byStringDescriptor([accordDescriptor]).list()

//returns just the hondaAccord configuration - **YESSSSSS**
def hondaAccordQuery = DeviceConfiguration.byStringDescriptorUsingOr([hondaDescriptor, accordDescriptor]).listDistinct()

injecteer 是我最喜欢的人。

【问题讨论】:

    标签: grails groovy grails-orm detachedcriteria


    【解决方案1】:

    使用criteria querynamed queries。它们都允许更好的链接

    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 )
    

    你应该知道,andor 什么连词合适

    更新 2

    有这么多ands 你什么都找不到...

    如果您启动像 blah( honda, accord ).list() 这样的查询,它会尝试使用 name='honda' AND name='accord' 查找 stringDescriptors,这是不可能的,因此它不会返回任何结果!

    这就是为什么我倾向于认为,您的域模型根本不允许此类查询 - 即使在 SQL 级别也是如此。

    你的属性应该是清晰可辨的,这样你就可以通过honda(type 'make')和accord(type'model')找到它不应该在“model”中寻找“honda”。

    单个DeviceConfiguration 实例是否可以包含多个StringDescriptors 的相同type

    【讨论】:

    • 谢谢!这对我来说绝对是朝着正确方向迈出的一步。但是我在为我的用例将查询串在一起时遇到了麻烦......
    • 我已经根据您的回答用我尝试过的方法更新了我的问题...有什么建议吗?
    • 非常感谢您迄今为止的帮助!很高兴知道可以在命名查询中使用 for 循环。但我似乎仍然无法得到我正在寻找的行为。我已经用我尝试过的方法更新了我的问题......如果你有更多的提示,我真的很感激他们:(
    • 在我的域中,我将添加一个约束,以防止任何单个 DeviceConfiguration 指向同名的 StringDescriptors...(例如,任何配置都不会指向 [name: make , value: honda][name: make , value: toyota])...所以我要做的是只查询引用 both的 DeviceConfigurations > 两个特定描述符 - [name: make, value: honda][name: model, value: accord]...
    • 啊,哎呀,我是个白痴。我现在明白了,谢谢你的帮助!我会更新我所做的,但它与您的答案基本相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    • 1970-01-01
    相关资源
    最近更新 更多