Jump to: navigation, search

EclipseLink/Development/Incubator/Extensions/FetchPlan

Extensions Incubator: FetchPlan

This incubator (bug 288307) is intended to develop the idea of fully specifying what is returned from a query when it is executed. Users often need to ensure a resulting entity graph has required attributed and relationships populated so that the result can be serialized. A FetchPlan allows the user to specify which children relationships and attributes need to be populated and then during the post processing of the query results these attributes are loaded.

FetchPlan Features

  • FETCH: Use a FetchPlan to ensure that resulting graph of entities is populated with AT LEAST the specified attributes and relationships.
  • COPY: Use a FetchPlan to create a copy of an entity graph with ONLY the specified attributes and relationships.
  • MERGE: Use a FetchPlan to merge a partial entity graph into a persistence context (EntityManager).


Download the Software

The incubator project is available in SVN @ http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/incubator/extensions/trunk/org.eclipse.persistence.example.jpa.fetchplan

The incubator is current being developed with dependencies on two example projects from trunk

The compile dependencies are configured on the org.eclipse.persistence.example.jpa.common project assuming that you have EclipseLink's trunk development projects checked out. If you do not, then remove the project dependencies and make this project depend on libraries that include your EclipseLink implementation, javax.persistence, and the JDBC driver you will use. Make sure this project also exports these dependencies.

Download the JAR

Just the implementation required to try this incubator in your development is available @ eclipselink-extension-incubator_fetchplan.jar. Note: This jar is manually updated and maintained as a best effort of the incubator developers

Feedback

If you encounter any issues, have a suggestion, or would like to contribute to this incubator please file a bug with the summary prefixed with [FetchPlan].

Usage Examples

FETCH Examples

Fetch of Basic and Relationships

FetchPlan fetchPlan = new FetchPlan(Employee.class);
fetchPlan.addAttribute("firstName");
fetchPlan.addAttribute("lastName");
fetchPlan.addAttribute("gender");
fetchPlan.addAttribute("salary");
fetchPlan.addAttribute("address");
fetchPlan.addAttribute("phoneNumbers");
 
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.salary > 0");
 
List<Employee> emps = query.getResultList();
 
// Force the fetch operation on the query result
JpaFetchPlanHelper.fetch(em, fetchPlan, emps);

FetchPlan with dynamic FetchGroup

In the following example only the fields required to populate the basic (direct-to-field) mappings and foreign key columns on the source table(s) necessary for the specified relationships.

FetchPlan fetchPlan = new FetchPlan(Employee.class);
fetchPlan.addAttribute("firstName");
fetchPlan.addAttribute("lastName");
fetchPlan.addAttribute("gender");
fetchPlan.addAttribute("salary");
fetchPlan.addAttribute("address");
fetchPlan.addAttribute("phoneNumbers");
 
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.salary > 0");
 
// Configure a dynamic FetchGroup based on the FetchPlan
query.setHint(QueryHints.FETCH_GROUP, fetchPlan.createFetchGroup());
 
List<Employee> emps = query.getResultList();
 
// Force the fetch operation on the query result
JpaFetchPlanHelper.fetch(em, fetchPlan, emps);

FetcPlan with FetchGroup and BATCH Reading

FetchPlan fetchPlan = new FetchPlan(Employee.class);
fetchPlan.addAttribute("firstName");
fetchPlan.addAttribute("lastName");
fetchPlan.addAttribute("gender");
fetchPlan.addAttribute("salary");
fetchPlan.addAttribute("address");
fetchPlan.addAttribute("phoneNumbers");
 
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.salary > 0");
 
// Configure a dynamic FetchGroup based on the FetchPlan
query.setHint(QueryHints.FETCH_GROUP, fetchPlan.createFetchGroup());
 
query.setHint(QueryHints.BATCH, "e.address");
query.setHint(QueryHints.BATCH, "e.phoneNumbers");
 
List<Employee> emps = query.getResultList();
JpaFetchPlanHelper.fetch(em, fetchPlan, emps);

COPY Examples

FetchPlan Copy of Employee names, address, and phoneNumbers

The result of the JpaFetchPlanHelper.copy method is an unmanaged graph of entities with ONLY the attributes specified in the FetchPlan plus all required attributes as defined by the mapping's fetch configuration. In this case all attributes of each employees address and phone numbers including the phone number's owner relationship back to the copied partial Employee.

Query query = em.createQuery("SELECT e FROM Employee e WHERE e.salary > 0");
 
FetchPlan fetchPlan = new FetchPlan(Employee.class);
fetchPlan.addAttribute("firstName");
fetchPlan.addAttribute("lastName");
fetchPlan.addAttribute("address");
fetchPlan.addAttribute("phoneNumbers");
 
List<Employee> emps = query.getResultList();
 
return JpaFetchPlanHelper.copy(em, fetchPlan, emps);

MERGE Examples

Basic Copy-Merge Example

This example uses a copy to create a partial unmanaged graph and then a merge to apply the changes made to the graph into the persistence context.

FetchPlan fetchPlan = new FetchPlan(Employee.class);
fetchPlan.addAttribute("firstName");
fetchPlan.addAttribute("lastName");
fetchPlan.addAttribute("address");
fetchPlan.addAttribute("phoneNumbers");
 
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = (SELECT MIN(ee.id) FROM Employee ee)");
query.setHint(QueryHints.FETCH_GROUP, fetchPlan.createFetchGroup());
 
Employee emp = (Employee) query.getSingleResult();
 
Employee copy = JpaFetchPlanHelper.copy(em, fetchPlan, emp);
 
// NOTE: setSalary will be ignored during the merge below since it is not in the FetchPlan
copy.setSalary(Integer.MAX_VALUE);
copy.setFirstName(emp.getLastName());
copy.setLastName(emp.getFirstName());
 
JpaFetchPlanHelper.merge(em, fetchPlan, copy);

Limitations of Use

  • Can FetchGroups be specified for dependent objects combining in the ideas from the EclipseLink/Development/Incubator/Extensions/NestedFetchGroup extension incubator?
  • Need to address what specifying an attribute means with respect to FetchGroups
  • Testing
    • FetchPlanAssert needs to be enhanced to address collections
  • Workarounds
    • The JPQL-Query cache is problematic as changes made to native queries wrapped within an EJBQueryImpl can be leaked between subsequent calls using the same JPQL. Current the FetchPlanHeler.create(Query) handles cloning the native query if it is in the query cache to avoid this leakage.

Integration Notes

During the design and implementation of this extension the final design for how this extension can be incorporated into the main project source is ongoing. The following are design notes captured to assist in this process when the incubator reaches maturity.