Mapping and querying a list of primitive types with JPA 2.0

Sometimes you just want to map a list of primitive types. For example, a Book entity has a list of tags and tags are just strings. So you want to do the following :

[sourcecode language=”java”]
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String title;
private Float price;
private String description;
private String isbn;
private Integer nbOfPage;
private List<String> tags = new ArrayList<String>();

}
[/sourcecode]

What happens when you do this with JPA 1.0 ? The ArrayList implements Serializable so the entire list gets serialized into a blob column. What are the other choices ? Well, because JPA maps entities, you can create a Tag entity (with an ID and a value) and have a list of tags :

[sourcecode language=”java”]
Entity
public class Book {
@Id
@GeneratedValue
private Long id;

private List<Tag> tags = new ArrayList<Tag>();

}

@Entity
public class Tag {
@Id
@GeneratedValue
private Long id;
private String value;

}
[/sourcecode]

That’s a shame to create a separate entity when what you want is just a String. Now with JPA 2.0 you can use the @ElementCollection annotation on a list :

[sourcecode language=”java”]
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;

@ElementCollection
@CollectionTable(name ="tags")
private List<String> tags = new ArrayList<String>();

}
[/sourcecode]

jpa2The @ElementCollection annotation will automatically map the list of strings into a table named BOOK_TAGS (<name of the entity>_<name of the attribute>). If you need to change the table’s name, just use the @CollectionTable annotation. The result is shown on the figure. The Book table contains all the Book entity attributes, and the TAGS table contains the BOOK_ID foreign key and the value of the tags.

If you then want to find all the books that have the tag ‘scifi’, you can just write the following JPQL query :

[sourcecode language=”sql”]
SELECT b FROM Book b WHERE b.tags = ‘scifi’
[/sourcecode]

I didn’t manage to make this query work with Hibernate 3.6. So I had to rewrite the JPQL statement usgin a JOIN. This way, the query works on both EclipseLink and Hibnerate

[sourcecode language=”sql”]
SELECT b FROM Book b JOIN b.tags t WHERE t = ‘scifi’
[/sourcecode]

Download the code of this example. It uses EclipseLink 2.0-M9 and the Derby database.

6 thoughts on “Mapping and querying a list of primitive types with JPA 2.0

  1. Thans a lot.
    What do you suggest if I need to store an Entity attribute that is an array of int?
    For instance if I have a “BingoCard” @Entity with a int[] numbers attribute?
    Is the separate table generated by @ElementCollection still suitable? Or there are other solutions, better from a disk space/performance point of view?

    Many thanks, Giovanni

  2. How would to write queries using Join with static metamodel having your approach? I think it’s not possible and you’ll end up with a separate entity.

  3. Hi
    What if I want to get Books that contains multiple tags?
    example;

    SELECT b FROM Book b JOIN b.tags t WHERE t IN (‘scifi’, ‘horror’, ‘thriller’)

Leave a Reply