如何检查给定列表是否是 GORM 中字段值的子集?
How do I check if a given list is a subset of a field value in GORM?
我正在开发某种带有可变字段的高级搜索功能。一些搜索字段是一些原始(ish)对象(字符串、枚举等)的列表。我希望能够检索值是某个给定列表的子集的记录。
为了说明,假设我有一个 Book
class(假设模型适合这种方式):
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']
的列表,可以搜索 cdickens
和 mtwain
的任何合作作品。我如何使用 GORM 的 where
构造来表达这一点?甚至可以用它来覆盖这个吗?
基本上,我想做的是:
Book.where {
authorFilter.every { it in authors }
}
这个问题有。不幸的是,where nor criteria 查询都没有 every()
等价物。但是有一个 hack 可能对你有用。但首先,我将扩展您的域模型。
领域模型
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()])
它是如何工作的。
您可以在我提到的 问题中了解此查询的工作原理。
我认为这并不比@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)
我的有点不同,因为 authorFilter
是 Author
域 class 实例的集合;我发现 MEMBER OF
表达式更容易工作,而且更真实地描述了真实数据的建模方式。
你可以看到我用 eachWithIndex
构建了多个 MEMBER OF
表达式,使用命名参数两侧的索引。它不是很漂亮,但我不相信有解决这个问题的方法并且仍然使用这种方法。
我认为@EmmanuelRosa 的方法可能是 'cleaner' 选项,但就逻辑而言,MEMBER OF
方法在我看来更有意义。
除了执行 HQL 查询之外,似乎没有更简单的方法来执行此操作。根据 this answer to a very similar question 的提示,我找到了解决问题的方法。
明确地说,Book
应该已经与使用 hasMany
构造的许多 String
相关:
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])
我正在开发某种带有可变字段的高级搜索功能。一些搜索字段是一些原始(ish)对象(字符串、枚举等)的列表。我希望能够检索值是某个给定列表的子集的记录。
为了说明,假设我有一个 Book
class(假设模型适合这种方式):
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']
的列表,可以搜索 cdickens
和 mtwain
的任何合作作品。我如何使用 GORM 的 where
构造来表达这一点?甚至可以用它来覆盖这个吗?
基本上,我想做的是:
Book.where {
authorFilter.every { it in authors }
}
这个问题有every()
等价物。但是有一个 hack 可能对你有用。但首先,我将扩展您的域模型。
领域模型
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()])
它是如何工作的。
您可以在我提到的
我认为这并不比@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)
我的有点不同,因为 authorFilter
是 Author
域 class 实例的集合;我发现 MEMBER OF
表达式更容易工作,而且更真实地描述了真实数据的建模方式。
你可以看到我用 eachWithIndex
构建了多个 MEMBER OF
表达式,使用命名参数两侧的索引。它不是很漂亮,但我不相信有解决这个问题的方法并且仍然使用这种方法。
我认为@EmmanuelRosa 的方法可能是 'cleaner' 选项,但就逻辑而言,MEMBER OF
方法在我看来更有意义。
除了执行 HQL 查询之外,似乎没有更简单的方法来执行此操作。根据 this answer to a very similar question 的提示,我找到了解决问题的方法。
明确地说,Book
应该已经与使用 hasMany
构造的许多 String
相关:
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])