gus
gus

Reputation: 191

@OneToMany mapping list size limit

Is there any way to limit the list's size of the @OneToMany relationship in JPA? Here's my code sample:

@OneToMany(mappedBy = "publication", cascade=CascadeType.PERSIST)
private List<Comment> commentList;

I'm using EclipseLink 2.3 JPA implementation. Thanks in advance.

Upvotes: 19

Views: 28251

Answers (4)

Stijn de Witt
Stijn de Witt

Reputation: 42075

The real problem is the collection itself. You should not model your business domain this way. This solution (of collections annotated with @OneToMany) is only viable for small collections (dozens of objects) and not for large ones (thousands of objects) which may very well be the case with comments. You really have to watch out with them as they can quickly grow out of control. I am using them at the moment only to model the collection of Roles associated with an Account, because I know that no account will ever have more than 9 roles in my domain and because the roles an account is in is so very vital to working with the account. For all other m-to-n relations I am using plain old queries.

Instead of adding a collection of comments to your object, add a reference to the object on Comment and explicitly get the comments you want using a query.

Define a named query on Comment to get the comments for a certain object (let's use Article):

@Entity
@NamedQueries(value={
    @NamedQuery(name=Comment.FOR_ARTICLE, query=
        "SELECT c FROM Comment c WHERE c.article = :article"
    )
})
public class Comment {
    // ...
    @ManyToOne
    @JoinColumn(name = "articleId")
    private Article article;
}

Then, use that named query i.c.w. Query.setMaxResults and Query.setFirstResult to explicitly control how many results to get and allow for paging etc:

@PersistenceContext
EntityManager em;

Article theArticle = ...;

Query query = em.createNamedQuery(Comment.FOR_ARTICLE, Comment.class);
query.setParameter("article", theArticle);
query.setFirstResult(0);
query.setMaxResults(10);
List<Comment> comments = (List<Comment>) query.getResultList();

To do paging, just setFirstResult to the first result corresponding with the page you want to display. E.G. to show results 20 .. 29, you would call setFirstResult(20).

Upvotes: 5

Nicolae Petridean
Nicolae Petridean

Reputation: 21

No real ortodox way of doing this. I would make the relation lazy, query for the parent objects. After wards do not initialize the lazy list, and run another query based on the first query, that runs on the child table. This way you can limit the result set on the main criteria and not on a join criteria. Or you can run only the second query (only on the child table), with pagination support.

Upvotes: 0

Desmond Zhou
Desmond Zhou

Reputation: 1409

You cannot do this in JPA and it doesn't make sense because mappings are designed to reflect the reality of how many objects are in the relationship.

Are you doing this because of performance? If so what you can do is to use a Lazy fetch style and use the Batchsize annotation to specific how many you want to fetch once:

*correction: @Batchsize is a Hibernate feature

@OneToMany(mappedBy = "publication", cascade=CascadeType.PERSIST, fetch=LAZY)
@BatchSize(size=16)
private List<Comment> commentList;

Then in your code, simply only iterate/loop to where you want in this mapped collection.

Either way, from my experience "hacking" mappings to do what Criterias/Querys are designed for is not a fruitful endeavor, when you need more control or performance-tuning than the @OneToMany explicitly provides, the best way might be to just make a query.

Upvotes: 4

jeha
jeha

Reputation: 10720

Part of the Bean Validation Specification (JSR-303) is the @Size(min=, max=) annotation:

Supported types are String, Collection, Map and arrays. Check if the annotated element size is between min and max (inclusive).

You could validate the collection.

@OneToMany(mappedBy = "publication", cascade=CascadeType.PERSIST)
@Size(min=1, max=10)
private List<Comment> commentList;

Upvotes: 23

Related Questions