繁体   English   中英

Grails:如何最好地构造一个休眠条件构建器来搜索与域实例的“ hasMany”关系

[英]Grails : how to best construct a hibernate criteria builder to search 'hasMany' relationships with domain instance

我正在执行grails项目,并希望利用休眠条件构建器来搜索域对象的实例。 我想找到其中“ hasMany”关系之一包含具有某些ID的域对象的实例。 这是我的意思的一个例子。

域对象

class Product {
   static hasMany = [ productOptions: ProductOption ]
}

class ProductOption{
   Option option
   static belongsTo = [ product: Product ]
}

class Option{
   String name
}

这是我的域结构的简化示例,并不包含所有关系。

Option可以是大小,颜色,品牌等。

我想实现的示例

可以说我有3个产品。

Product 1 is red, small and by brandx

Product 2 is blue, small and by brandx

Product 3 is yellow, medium and by brandz

我有一些需要介绍的场景。

场景1

  • 查找蓝色,小型和brandx产品。 因此,在这种情况下,我只应退回产品2。

方案2

  • 查找红色或蓝色且尺寸较小的产品。 因此,应该同时返回产品1和产品2。

场景3

  • 查找brandx或brandz的产品。 因此,所有产品都应退货。

我希望这能涵盖所有情况。

这是当前尝试的一个示例。

def c = Product.createCriteria()
def products = c.list{
    and {
        productOptions {
            'option' {
                idEq(1)//1 is the id of the blue option
            }
        }
        productOptions {
            'option' {
                idEq(5)//5 is the id of the small size option
            }
        }
        productOptions {
            'option' {
                idEq(10)//10 is the id of the brandx brand option
            }
        }
    }
}

此示例的and部分未包含所有选项,并且失败。 我如何最好地做到这一点? 我可以使用Grails休眠标准构建器来实现这一目标吗? 请让我知道其他信息是否有帮助。

在此先感谢您提供的任何指导。

您正在寻找的是Groovy的Object.every(Closure)

assert [1,2,3] .every {it <4} == true assert [1,2,3] .every {it <3} == false

every()方法返回一个布尔值,该布尔值指示Closure是否对集合中的每个项目求值为true。

不幸的是,没有一个查询方法(where,criteria和HQL)提供与every()等效的查询方法。 但是...您可以使用HQL作弊。

注意:因为条件查询不支持HQL HAVING子句的等效项,所以条件查询也不在哪里。

场景1-骇客

def ids = [4, 5, 6] // List of Option ids.

Product.executeQuery '''
select prd from Product as prd 
    join prd.productOptions as prdopts 
    join prdopts.option as opt 
where opt.id in :ids 
group by prd
having count(prd) = :count''', [ids: ids.collect { it.toLong() }, count: ids.size().toLong()]

这个怎么运作

该查询首先选择id列表中具有任何 Option的所有Product 只要产品具有至少一个选项,它将被退回。

这产生了针对其具有的每个匹配选项列出Product的副作用。 例如,如果一个Product具有三个Option ,则该产品将被返回三次。 GROUP BY子句使查询可以过滤掉那些重复的清单。

但是,这些重复项是此黑客的关键:如果ID列表是唯一列表,并且Product一次不具有相同的Option ,那么如果重复项的数量相等,则Product具有所有必需的Option项到ID的数量。 这就是HAVING子句通过计算Product的数量所做的事情。

场景2和3

场景2和3可以由同一查询处理。 我将放弃一致性并选择一个Criteria查询,因为它最能达到此目的。

// Example params for scenario 2
def qparams = [
    or: [1, 2], // These are color Option IDs
    and: 5 // This is a size Option ID
]

// Example params for scenario 3
def qparams = [
    or: [10, 11] // These are brand Option IDs
]

Product.withCriteria {
    productOptions {
        option {
            if(qparams.and) eq('id', qparams.and.toLong())
            inList('id', qparams.or.collect({ it.toLong() }))               
        }
    }
}

总是期望or参数,但是if块仅在指定了and参数的情况下才添加and约束。 请注意,这些ID只是选项ID,因此具有一定的灵活性。 例如,您可以搜索任何没有大小限制的颜色。

关于ID ...

您会注意到,在我的示例中,我将IDS从Integers转换为Longs。 如果您的ID来自数据库,那么它们已经是Longs,因此您可以取出该代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM