我正在创建一个带有Grails的玩具Q& A网站,以便学习该平台。 我有两个域,帖子和标签,它们之间有很多关系。我想打印一个带有标签的帖子列表。
我不能使用延迟抓取,因为我会遇到N + 1选择问题
我不能使用急切的抓取,因为它使用左连接,我将无法正确分页结果。
因此我决定使用以下代码手动获取标记:
static def getList(params) {
ArrayList questions = Question.list(params)
def questionMap = [:]
questions.each {
questionMap.put(it.id, it)
}
if(questions.size()>0) {
Tag.executeQuery('SELECT q.id, t FROM Tag t JOIN t.questions q \
WHERE q.id in ( :list ) ', [ list:questions.collect{ it.id } ] ).each { questionMap.get(it[0]).tags.add(it[1]) }
}
return questions
}
然而,当我在视图中打印标签时:
<g:each in="${questions}" var="question">
${question.title}
<g:each in="${question.tags}" var="tag">
${tag?.text}
</g:each>
</g:each>
无论如何,每个问题都会执行一个查询! 这里推荐的方法是什么?
答案 0 :(得分:1)
您的代码存在的问题是您没有对Tag
查询的结果做任何事情。此外,它是一种更好的方法,可以为多对多关系建立连接类。例如,如果您看到Spring Security Core插件,则会显示User
,Role
和名为UserRole
的联接类。 Here是示例类。
所以我的建议是:
class Tag {
...
}
class Question{
...
}
class QuestionTag implements Serializable {
Tag tag
Question question
static mapping = {
id composite: ['tag','question']
...
}
//need to override equals and hashCode
}
要存储标记的结果,您可以为您的类添加瞬态字段:
课堂问题{ def标签 静态瞬态= [&#39;标签&#39;] //删除hasMany。 }
您现在可以执行HQL
,在问题列表中查找问题实例并设置tags
属性。由于您使用的是一个不返回单个类的HQL,因此结果不会映射为Tag
对象,因此访问权限略有不同。
HQL查询可以返回域类实例或指定的数组 查询选择单个字段或计算值时的数据
答案 1 :(得分:0)
你在说
“我不能使用渴望的提取,因为它使用左连接和我 将无法正确分页结果。“
您可以使用session.createFilter为协会进行分页。
此示例(版权所有Burt Beckwith)来自Burt Beckwith's book Programming Grails来自“第5章,Hibernate,session.createFilter”
// example from Burt Beckwith's book "Programming Grails", (c) Burt Beckwith
class Branch {
String name
List visits
static hasMany = [visits: Visit]
List<Visit> getVisitsByPage(int pageSize, int pageNumber) {
Branch.withSession { session ->
session.createFilter(visits, '')
.setMaxResults(pageSize)
.setFirstResult(pageSize * pageNumber)
.list()
}
}
}
我建议购买this book