grails paginate with a list from a 1:m relationship
In the case below an author object has an existing list of 'books'. How do you paginate through this list of books if the controller 开发者_StackOverflow社区already has an 'author' object and you do not want to go back to the DB with another request of Book.findAll("from Book as b where b.author=:author", [author:author], [max:10, offset:5])
class Author {
String name
static hasMany = [ books:book]
}
class Book {
String title
static belongsTo = [ author:Author ]
}
long time no see!
I would certainly agree with Rob here.
What you will see in the sql logs is multiple queries being made for the author and books in both cases. Grails defaults to lazy loading collections, and so at the statement
def author= Author.findByName(params.id)
You have only loaded the author, not the books.
Adding an extra statement to load the books in the normal paginated way will be more efficient, and more maintainable, as it is cleaner and more obvious what it is doing.
This is the style I normally employ to get this kind of data.
def timeline = {
println "timeline[" + params+ "]"
if (params.id) {
def author= Author.findByName(params.id)
def books = Book.withCriteria {
eq('author', author)
firstResult(5)
maxResults(10)
}
def totalBooks = Book.createCriteria().count {
eq(author, author)
}
...
}
Also, (not sure on this), but the size() statement on the books collection will trigger a count query, but may also trigger other queries too, so it pays when you have such a large data set to be specific in what you get GORM to do.
(updated as per Bills comment below)
I admit I am a grails newbie - I reckon I must be missing something.
So after a lot of messing here is my very ugly solution:
def timeline = {
println "timeline[" + params+ "]"
if (params.id) {
def author= Author.findByName(params.id)
def allbooks = author?.books as List
def max=params.max?:(allbooks.size()>2 ? 2: allbooks.size())
def offset=params.offset?:(0)
offset = offset as int
max = max as int
def start = offset*max > allbooks.size()-1 ? allbooks.size()-1 : offset*max
def end = ((offset*max)+max-1) > allbooks.size()-1 ? allbooks.size() -1 : ((offset*max)+max-1)
def books= allbooks.size() > 0?allbooks[(start)..(end)]:allbooks
def bookCount = allbooks.size()
println "max:" + params.max + ""
println "books.size:" + books.size() + ", bookCount:" + bookCount
[author, bookCount, books]
}
精彩评论