How can I do paging with @OneToMany collections
Asked Answered
B

2

19

Suppose I have a Post entity and a Comment entity and a one to many relationship:

@Entity class Post {
    ...
    @OneToMany
    List<Comment> comments;
    ...
}

How can I achieve paging like this:

Post post = //Find the post.
return post.getComments().fetch(100, 10); // Find the 11th page (page size 10);

Is it possible to emulate dynamic paging with @OneToMany collections on top of JPA, or do we have to rewrite the association mechanism of JPA totally ? (e.g. create a PersistentList collection type that could manage the paging, sorting and searching).

P.S.: I recently found the Play! framework uses a very interesting lib on top of JPA: Siena. Siena is very easy to use, and is a good abstraction on top of JPA/Hibernate. But I can't find how to do paging with its associations.

Update:

Play framework has a query syntax similar to Django:

Post.findAll().from(100).fetch(10);  // paging

where

Post.findAll() 

will return a JPAQuery object, a customized query type in Play.

But with associated collections, e.g.:

Post.comments

will just return a List, which doesn't support paging or other queries.

I was wondering how to extend it, so that

Post.comments

will also return a JPAQuery object or similar, then you can query on the "query" collection:

Post.comments.from(100).fetch(10);

or insert a new Comment without actually fetching any of the comments:

Post.comments.add(new Comment(...));

On my first thought, we could create a subclass of List, then the Post class would become:

@Entity class Post {
    ...
    @OneToMany
    QueryList<Comment> comments;
    ...
}

and QueryList will have fetch(), from() methods that indirect to JPAQuery's.

But I don't know whether Hibernate/JPA will recognize this, or interfere with it.

Bleier answered 19/10, 2010 at 16:48 Comment(0)
A
9

Is it possible to emulate dynamic paging with @OneToMany collections on top of JPA (...)

Not supported. The standard approach would be to use a JPQL query to retrieve the comments for a given post and and to use Query#setFirstResult(int) and Query#setMaxResults(int).

On my first thought, we could create a subclass of List, (...). But I don't know whether Hibernate/JPA will recognize this, or interfere with it.

It obviously won't without an heavy patch to drastically change the default behavior.

Allcot answered 19/10, 2010 at 17:35 Comment(6)
BTW. I found that Hibernate will "intercept" the @OneToMany Collection, and indirect it into a query. So is it possible to "plugin" Hibernate system with a customized collection type (e.g. @OneToMany LazyQueryList, which has a fetch(start, offset) method), that Hibernate will recognize?Bleier
@Visus It should be possible to patch Hibernate, which is very different from a plugin mechanism, and this won't be a trivial patch. Good luck if you decide to go this direction.Allcot
Thanks for the clarification. I'm new with hibernate, and a heavy patch is definitely beyond my ability. But I'm still stuck with how to use associations effectively. I saw you talk about projects using hibernate in a bad way - 'not using associations because they were scared to "fetch the whole database"', in a reply to another question. I'd really like to know how NOT to retrieve a whole collection. Or, in the case of manually creating JPQL queries for the collection, does that mean we use the association collection only for the mapping? How can we set them back to Post.comments?Bleier
I'd really like to know how NOT to retrieve a whole collection Make it LAZY, or maybe even EXTRA lazy. Or, in the case of manually creating JPQL queries for the collection, does that mean we use the association collection only for the mapping? For querying also.Allcot
So I guess when the collection is small, just use something like Post.getComments(); and when it is potentially large, avoid the Post.getComments() and make another query (paged if needed), and use the result list independently. Is that the right practice?Bleier
@Visus That's at least what I consider as the right practice.Allcot
F
4

I think the "right" way might be more like:

@Entity
class Post {
    ...

    public GenericModel.JPAQuery getComments() {
        return Comment.find("post_id = ?", post_id);
    }
}

and then use one of the fetch methods in JPAQuery:

// fetch first page of results, 25 results per page
post.getComments().fetch(1,25);
Fulfillment answered 21/1, 2011 at 22:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.