Mapping collection of simple type in JPA using @ElementCollection

JPA framework provides good support for mapping collections of value types. The value types can be either simple types like Integer or String, or custom embeddable types. In this short post I would like to present two most popular mappings with simple types.

Mapping a set

Assume that there is a requirement to store a collection of unique names in an entity. In JPA it could be as simple as defining a plain Set of String in entity class and adding few annotations:

@Entity
public class Author {
  @Id
  protected long id;

  @ElementCollection
  @CollectionTable(name = "author_name",
        joinColumns = { @JoinColumn(name = "author_id") })
  @Column(name = "name")
  protected Set<String> names = new HashSet<>();

The first annotation @ElementCollection is required and is needed to inform JPA provider that a collection of value types is used. The rest of the annotations are optional and are used to customize the schema.

The @CollectionTable annotation specifies the name of the DB table where the collection values are stored. In this case the new table is named author_name. This new table refers to the parent entity Author through a foreign key. The definition of the column holding the foreign key is specified in joinColumns parameter.

The @Column annotation defines the properties (e.g. name) of the column in the new table where the values of the Set are stored.

Mapping a list

Common Set implementations (HashSet and TreeSet) in Java does not allow duplicates and also does not preserve the order. If one of these features is required, the List can be used instead of Set:

@Entity
public class Author {
  @Id
  protected long id;

  @ElementCollection
  @CollectionTable(name = "author_name",
        joinColumns = { @JoinColumn(name = "author_id") })
  @Column(name = "name")
  protected List<String> names = new ArrayList<>();

Actually, the example is almost exactly the same as above. The list can contain duplicates and they will be preserved to the database.

Preserving order in a list

Even if you store items in a list in a particular order, the order will not be restored when the entity is loaded again from the database. In fact, the order of the items in the list is DBMS-dependent. To overcome this we can add extra annotation:

  @OrderColumn(name = "order_idx")   // optional; preserves order of the list

The annotation defines the new column in the collection table which is used for ordering only. JPA provider (e.g. Hibernate) manages this column internally. On persist or update it updates the column with the position of the item and on retrieve it uses the column to order items.

Preserving the order using @OrderColumn may seem like a good idea but in practice it may cause many problems. The order may be good for one application view but on other views we may want to use different ordering. The second problem is that keeping order reduces performance because JPA provider has to internally read and update values in order column. Additionally, the order is usually not a part of application data/domain so there may be no good reason to keep it in the database.

Due to the above issues it is good to check advantages and disadvantages in each particular case before using @OrderColumn.

About Robert Piasecki

Husband and father, Java software developer, Linux and open-source fan.
This entry was posted in Database, JPA and tagged , , . Bookmark the permalink.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.