Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/JPA/Collectionordering"

(New page: == Maintain Collection Ordering == In some applications it is valuable to maintain collection ordering within the Java application. JPA provides support for ordering the traget of a colle...)
 
(Collection Order Preservation (JPA 1.0))
 
(17 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Maintain Collection Ordering ==
+
__NOTOC__
  
In some applications it is valuable to maintain collection ordering within the Java application. JPA provides support for ordering the traget of a collection mapping (OneToMany, ManyToMany) but the order is not preserved in-memory.
+
== 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, [[EclipseLink/Examples/JPA/2.0/OrderColumns|OrderColumns]].
 +
 
 +
=== Configuration ===
 +
 
 +
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:
 +
 
 +
# Ensure that a ''index'' attribute is mapped (@Basic) in the target entity of the collection where order maintenance is required.
 +
# Ensure that the collection is mapped and has OrderBy("index")  specified
 +
# 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.
 +
 
 +
<source lang="java">
 +
@Entity
 +
@IdClass(LineItem.ID.class)
 +
@Table(name = "PO_LINE_ITEM")
 +
public class LineItem implements Serializable {
 +
@Id
 +
@Column(name = "ORDER_NUM", insertable = false, updatable = false)
 +
private String orderNumber;
 +
 
 +
@ManyToOne
 +
@JoinColumn(name = "ORDER_NUM")
 +
private Order order;
 +
 
 +
@Column(name = "LINE_NUM")
 +
private int lineNumber = -1;
 +
 
 +
@Id
 +
@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;
 +
}
 +
 
 +
// ...
 +
</source>
 +
 
 +
==== Step 2: Map the Collection with Ordering ====
 +
 
 +
Within the '''Order.lineItems''' mapping the ordering is configured using the mapped index attribute (lienNumber):
 +
 
 +
<source lang="java">
 +
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
 +
@OrderBy("lineNumber")
 +
@PrivateOwned
 +
private List<LineItem> lineItems = new ArrayList<LineItem>();
 +
</source>
 +
 
 +
==== Step 3: Configure the Event Listener ====
 +
 
 +
The '''CollectionIndexSessionListener''' is configured using a [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/config/SessionCustomizer.html SessionCustomizer].
 +
 
 +
<source lang="java">
 +
public class ConfigureCollectionIndexing implements SessionCustomizer {
 +
 
 +
public void customize(Session session) throws Exception {
 +
CollectionIndexSessionListener listener = new CollectionIndexSessionListener();
 +
 
 +
listener.addCollection(session, Order.class, "lineItems", "lineNumber");
 +
 
 +
session.getEventManager().addListener(listener);
 +
}
 +
 
 +
}
 +
</source>
 +
 
 +
The use of the SessionCustomizer is configured in the persistence unit properties:
 +
 
 +
<source lang="xml">
 +
<persistence-unit name="persist-order" transaction-type="RESOURCE_LOCAL">
 +
<class> model.Product</class>
 +
<class> model.Order</class>
 +
<class> model.LineItem</class>
 +
<properties>
 +
...
 +
<property name="eclipselink.session.customizer" value="model.ConfigureCollectionIndexing"/>
 +
</properties>
 +
</persistence-unit>
 +
</source>
 +
 
 +
== Downloading and running the Example ==
 +
 
 +
The example is available for download here: [http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.persist-order/example-collection-order.zip example-collection-order.zip].
 +
 
 +
''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 [http://www.eclipse.org/downloads 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 build.properties 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'''.

Latest revision as of 10:48, 30 November 2009


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.

Configuration

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.

@Entity
@IdClass(LineItem.ID.class)
@Table(name = "PO_LINE_ITEM")
public class LineItem implements Serializable {
	@Id
	@Column(name = "ORDER_NUM", insertable = false, updatable = false)
	private String orderNumber;
 
	@ManyToOne
	@JoinColumn(name = "ORDER_NUM")
	private Order order;
 
	@Column(name = "LINE_NUM")
	private int lineNumber = -1;
 
	@Id
	@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)
@OrderBy("lineNumber")
@PrivateOwned
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");
 
		session.getEventManager().addListener(listener);
	}
 
}

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>
	<properties>
		...
		<property name="eclipselink.session.customizer" value="model.ConfigureCollectionIndexing"/>
	</properties>
</persistence-unit>

Downloading and running the Example

The example is available for download here: example-collection-order.zip.

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 build.properties 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.