Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: for the plan.

Jump to: navigation, search


Collection Order Preservation (JPA 1.0)

In some applications it is valuable to maintain collection ordering within the Java application. This requires that the order of a collection is maintained between writes and reads.

EclipseLink does provide support for ordering the target of a collection mapping (OneToMany, ManyToMany) but the order is not preserved in-memory and is not transparently saved. This example illustrates how an index column can be mapped in the target of a OneToMany mapping and used during the lifecycle of the entities to ensure the order set in the application is maintained when the collection is persisted and re-read.

Note: Transparent support for order preservation will be provided in EclipseLink 2.0 as part of its JPA 2.0 implementation. This example is intended to help those using JPA 1.0 who need this functionality in EclipseLink 1.0 or 1.1. See, OrderColumns.


In this example a simple Order domain model is used when an Order has a collection of LineItem and each of these has a Product. To configure things a developer must do the following:

  1. Ensure that a index attribute is mapped (@Basic) in the target entity of the collection where order maintenance is required.
  2. Ensure that the collection is mapped and has OrderBy("index") specified
  3. Configure the use of the provided CollectionIndexSessionListener

Step 1: Map an Index Attribute

Within the LineItem an additional index attribute is added. Since this attribute is intended to be transparent to the application its set method is protected. This method will be reflective used by the session-event-listener.

@Table(name = "PO_LINE_ITEM")
public class LineItem implements Serializable {
	@Column(name = "ORDER_NUM", insertable = false, updatable = false)
	private String orderNumber;
	@JoinColumn(name = "ORDER_NUM")
	private Order order;
	@Column(name = "LINE_NUM")
	private int lineNumber = -1;
	@Column(name = "PROD_ID", insertable = false, updatable = false)
	private int productId;
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "PROD_ID")
	private Product product;
	private int quantity;
	private double price;
	// ...
	public int getLineNumber() {
		return this.lineNumber;
	// ...

Step 2: Map the Collection with Ordering

Within the Order.lineItems mapping the ordering is configured using the mapped index attribute (lienNumber):

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<LineItem> lineItems = new ArrayList<LineItem>();

Step 3: Configure the Event Listener

The CollectionIndexSessionListener is configured using a SessionCustomizer.

public class ConfigureCollectionIndexing implements SessionCustomizer {
	public void customize(Session session) throws Exception {
		CollectionIndexSessionListener listener = new CollectionIndexSessionListener();
		listener.addCollection(session, Order.class, "lineItems", "lineNumber");

The use of the SessionCustomizer is configured in the persistence unit properties:

<persistence-unit name="persist-order" transaction-type="RESOURCE_LOCAL">
	<class> model.Product</class>
	<class> model.Order</class>
	<class> model.LineItem</class>
		<property name="eclipselink.session.customizer" value="model.ConfigureCollectionIndexing"/>

Downloading and running the Example

The example is available for download here:

Note: While it was developed and tested against EclipseLink 1.1 it should work with earlier versions of EclipseLink and can be easily transalted to work with TopLink releases using native ORM.

In order to run this example you must have EclipseLink installed on the machine and must have a relational database with its JDBC driver available. In order to customize the example you must:

  • To run using ANT you must configure the file
  • To customize the database you must edit src/META-INF/persistence.xml

In order to verify the database schema creation and population run testing.CreateDatabase. To perform all of the tests run testing.AllTests.

Back to the top