Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
EclipseLink/Development/JPA 2.0/ordered lists
Contents
Persisting Order
Issue Summary
JPA 2.0 specification has added functionality requiring the provider to persist list item indexes when mapped by the user. The provider must also track changes to an index.
See JPA 2.0 ED section 10.1.36 for details.
Additional requirements
- Solution should enable the storage of duplicates in ManyToMany lists. See bug 256978.
- Must offer flexibility in the naming and type of the database index columns to ensure users implementing their own work-arounds can easily upgrade to this implementation
General Solution
Ordered List support is currently available in EclipseLink. Order of collection items is tracked and updates and merges occur as a result of changes. What this feature requires is that an additional field be managed by EclipseLink that is not mapped in the object model, similar to the Uni-directional OneToMany mappings. This additional field will store the index of each item in the collection.
As all collection mappings will need to support this functionality the best approach is to make CollectionMapping able to write indexes. ChangeRecords are already aware of order changes but the mappings are unable to write the changes.
It would be favourable to be able to restrict the number of updates of the target row to one even if the target object has other changes. This may be possible by allowing the mapping to force the write of the target object and add index to the query.
There is a potential enhancement that allows the provider to fabricate artificial indexes to allow for efficient insertion. For example if there were 3 items in the list EclipseLink could assign index 1, 3, and 9 to these objects. Order would be maintained and should another instance be inserted into the list only one row update would be required instead of the minimal two. This should only be considered as a future enhancement to this feature.
Requirements
Main use case
The Collection used in ToMany relationship should be a List.
public class Employee { private List<Dealer> dealers; ... @OneToMany(cascade={PERSIST, MERGE}) @JoinColumn(name="FK_EMP_ID") @OrderColumn(name="ORDER") public List<Dealer> getDealers() { return dealers; } ... }
List members saved together with their indexes in the List:
Employee employee = new Employee(); Dealer dealerA = new Dealer("A"); employee.getDealers().add(dealerA); Dealer dealerB = new Dealer("B"); employee.getDealers().add(dealerB); Dealer dealerC = new Dealer("C"); employee.getDealers().add(dealerC); em.persist(employee);
DEALER_ID FK_EMP_ID NAME ORDER 33 5 A 0 34 5 B 1 35 5 C 2
The indexes updated if the List member(s) removed:
employee.getDealers().remove(dealerB);
DEALER_ID FK_EMP_ID NAME ORDER 33 5 A 0 35 5 C 1
the order changed:
employee.getDealers().remove(dealerA); employee.getDealers().add(dealerA);
DEALER_ID FK_EMP_ID NAME ORDER 33 5 A 1 35 5 C 0
new member(s) added:
Dealer dealerD = new Dealer("D"); employee.getDealers().add(dealerD);
DEALER_ID FK_EMP_ID NAME ORDER 33 5 A 1 35 5 C 0 35 5 D 2
Open Issues
Non Contiguous Index values
What if the collection is altered directly (not through Eclipselink) in the db so that the indexes are no longer a contiguous sequence of numbers from 0 to size-1?
Some elements removed from the beginning or the middle:
DEALER_ID FK_EMP_ID NAME ORDER 35 5 C 0 35 5 D 2
Some elements' order is null;
DEALER_ID FK_EMP_ID NAME ORDER 35 5 C 35 5 D
Some elements have equal ordered id values
DEALER_ID FK_EMP_ID NAME ORDER 35 5 C 3 35 5 D 3
How do we read back such "damaged' lists into Java app.?
- Should we throw an exception?
- Try to cure the list by assigning (sometimes randomly) the indexes?
- Insert null element into the List that corresponds to missing index (note that then the list size will be greater than the real number of objects)?
Indexing new elements in un-instantiated IndirectLists
When an IndirectList has new items added it does not force the entire list to be loaded. This means that during commit you need to assign new index values without necessarily having all of the contents of the list loaded. In my EclipseLink/Examples/JPA/Collectionordering example for EclipseLink 1.1 i am addressing this with a combination of a query for the max index value as well as forcing an optimistic locking update of the parent object if it supports it.
Work Required
- Develop model for testing
- approx 5 days - including all collection mapping types and maps
- Update EclipseLink
- approx 10 days - prototype mappings writing additional fields
- approx 10 days - implementing mapping support
- approx 3 days - JPQL INSERT() updates
- approx 3 days - verifying change detection/tracking support
- approx 2 days - Process annotations/XML