如何检查给定列表是否是GORM中字段值的子集?

时间:2015-11-22 18:22:32

标签: grails gorm

我正在研究某种带有可变字段的高级搜索功能。一些搜索字段是一些原始(ish)对象(字符串,枚举等)的列表。我希望能够检索其值是某个给定列表的子集的记录。

为了说明,我说有一个Book类(假设模型适合这种方式):

class Book {
    ...
    List authors = []
    ...
}

另外说我们有以下书籍记录:

Book(title: 'Great Expectations of Tom Sawyer', authors: ['cdickens', 'mtwain'])
Book(title: 'Huckleberry Potter in Bleak House', authors: ['cdickens', 'mtwain', 'jrowling'])
Book(title: 'A Christmas Carol', authors: ['cdickens'])

然后,我提供了一份作者(姓名)authorFilter = ['cdickens', 'mtwain']的列表,以搜索cdickensmtwain的任何协作作品。我如何使用GORM的where构造表达这一点?甚至可以用它来掩盖它吗?

基本上,我想做的是:

Book.where {
    authorFilter.every { it in authors }
}

3 个答案:

答案 0 :(得分:0)

这个问题有come up before。不幸的是,在哪里,条件查询的等价物都是every()。但是有一个可能适合你的黑客攻击。但首先,我将扩展您的域模型。

域模型

class Book {
    String title

    static hasMany = [authors: Author]
    static belongsTo = Author
}

class Author {
    String name

    static hasMany = [books: Book]
}

HQL查询

使用上述域模型,您可以使用以下HQL查询。

def hql = """
SELECT b FROM Book AS b
INNER JOIN b.authors AS a
WHERE a.name in :authors
GROUP BY b
HAVING COUNT(b) = :count
"""

def books = Book.executeQuery(hql, [authors: authorFilter, count: authorFilter.size()])

工作原理。

您可以在我提到的other问题中了解此查询的工作原理。

答案 1 :(得分:0)

我认为这不比@ EmmanuelRosa更好,但我有另一种使用HQL和executeQuery方法的方法。

使用他在答案中给出的相同域名模型,我使用MEMBER OF表达式来限制结果。

def authorFilter = [Author.get(1)]

def authorMemberOfRestriction = ""
def namedParameters = [:]

authorFilter.eachWithIndex{ aut, ind ->
    authorMemberOfRestriction += ":author${ind} MEMBER OF b.authors AND "
    namedParameters.put("author" + ind, aut)
}

namedParameters.put('count', authorFilter.size())

def hql = """
FROM Book b 
WHERE 
(
${authorMemberOfRestriction}
size(b.authors) = :count
)
"""

def books = Book.executeQuery(hql, namedParameters)

Mine有点不同,因为authorFilterAuthor域类实例的集合;我发现MEMBER OF表达式的工作要容易得多,而且更真实地描述了如何对实际数据进行建模。

您可以看到我使用MEMBER OF构建多个eachWithIndex表达式,使用命名参数两侧的索引。它不是很漂亮,但我不相信有办法解决这个问题,但仍然使用这种方法。

我认为@ EmmanuelRosa的方法可能是'清洁剂'选项,但就逻辑而言,MEMBER OF方法在我的脑海中更有意义。

答案 2 :(得分:0)

除了执行HQL查询之外,似乎没有更简单的方法。从this answer to a very similar question获取提示,我找到了解决问题的方法。

要明确的是,Book应该已经使用String构造与许多hasMany有关:

class Book {
    ...
    static hasMany = [authors: String]
    ...
}

获取结果:

def results = Product.executeQuery("select p from Products p join p.tags t where t in :tags", [tags: givenTags])