Grails:如何最好地构建休眠条件生成器以搜索与域实例的"hasMany"关系



我正在一个grails项目中工作,希望利用hibernate标准构建器来搜索域对象的实例。我想找到其中一个"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

  • 寻找蓝色,小品牌的产品。在这种情况下,我应该只返回Product 2。

场景2

  • 查找红色或蓝色且尺寸较小的产品。所以Product 1和Product 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标准构建器来实现这一点吗?请让我知道额外的信息是否有帮助。

提前感谢您提供的指导。

你要找的是Groovy的Object.every(Closure)的等号。

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

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

不幸的是,没有任何查询方法(where、criteria和HQL)提供等价的every()。但是…你可以用HQL作弊。

注意:nor 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 列表中具有任何OptionProduct。只要一个产品至少有一个选项,它将被返回。

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

然而,这些重复是这个hack的关键:如果id列表是一个唯一的列表,并且Product s没有超过一次具有相同的Option,那么Product具有所有需要的Option s,如果重复的数量等于id的数量。这就是HAVING子句通过计算Product s的数量所做的。

场景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() }))               
        }
    }
}

总是需要参数,但是如果指定了参数,则if块只添加约束。注意,这些id都只是Option id,所以您有一些灵活性。例如,您可以搜索任何颜色而不受大小限制。

关于id…

您会注意到,在我的示例中,我将IDS从整数转换为long。如果你的id来自数据库,那么它们已经是long了,所以你可以把代码拿出来。

最新更新