Grails:如何最好地构建一个hibernate标准构建器来搜索“hasMany'与域实例的关系

时间:2015-09-30 00:59:44

标签: grails hibernate-criteria

我正在开发一个grails项目,并希望利用hibernate标准构建器来搜索域对象的实例。我想找到其中一个有很多人的例子。关系包含具有特定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

  • 查找蓝色,小巧和品牌的产品。所以在这种情况下我应该只返回产品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 hibernate条件构建器来实现这一目标吗?如果有其他信息有帮助,请与我们联系。

提前感谢您提供的任何指导。

1 个答案:

答案 0 :(得分:2)

您正在寻找的内容相当于Groovy的Object.every(Closure)

断言[1,2,3]。每个{it< 4} == true 断言[1,2,3]。每个{it< 3} == false

every()方法返回一个布尔值,指示对于集合中的每个项,Closure的计算结果是否为真。

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

注意:Where和Criteria查询都会执行,因为它们不支持等效的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中Product 任何 的所有Option 列表。只要产品至少有一个选项,它就会被退回。

这会产生为其拥有的每个匹配选项列出Product的副作用。例如,如果Product有三个Option s,那么产品将返回三次。 GROUP BY子句使查询过滤掉那些重复的列表。

但是,这些重复项是此次攻击的关键:如果ID列表是唯一列表,并且Product不多次Option,则{{1}如果重复数量等于ID的数量,则具有所有必需的Product。这就是HAVING子句通过计算Option s的数量来实现的。

场景2& 3

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

Product

始终需要参数,但 if 块仅在时添加约束参数已指定。请注意,这些ID都只是选项ID,因此您具有一定的灵活性。例如,您可以搜索没有大小约束的任何颜色。

关于ID ...

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