| /******************************************************************************* | |
| * Copyright (c) 1998, 2009 Oracle. All rights reserved. | |
| * This program and the accompanying materials are made available under the | |
| * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
| * which accompanies this distribution. | |
| * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
| * and the Eclipse Distribution License is available at | |
| * http://www.eclipse.org/org/documents/edl-v10.php. | |
| * | |
| * Contributors: | |
| * dclarke - Bug 288307: Extensions Incubator - FetchPlan | |
| ******************************************************************************/ | |
| package example; | |
| import java.util.List; | |
| import javax.persistence.EntityManager; | |
| import javax.persistence.Query; | |
| import model.Employee; | |
| import model.Gender; | |
| import org.eclipse.persistence.config.QueryHints; | |
| import org.eclipse.persistence.extension.fetchplan.FetchPlan; | |
| import org.eclipse.persistence.extension.fetchplan.JpaFetchPlanHelper; | |
| import org.eclipse.persistence.jpa.JpaHelper; | |
| @SuppressWarnings("unchecked") | |
| public class FetchPlanExamples { | |
| /** | |
| * Query for all employees with a salary greater then zero using a | |
| * FetchGroup to only load id, firstName, lastName, gender, salary, and | |
| * version and then fetch their address and phone numbers using the same | |
| * FetchPlan. | |
| */ | |
| public List<Employee> employeesFetchAddressAndPhones(EntityManager em) { | |
| 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(); | |
| JpaFetchPlanHelper.fetch(em, fetchPlan, emps); | |
| return emps; | |
| } | |
| /** | |
| * Similar to {@link #employeesFetchAddressAndPhones(EntityManager)} but the | |
| * loading of the related address and phoneNumbers is optimized using batch | |
| * reading. | |
| */ | |
| // Note: FetchGroup with FETCH (JOIN) does not work - see bug XXX | |
| public List<Employee> employeesFetchAddressAndPhones_optimized(EntityManager em) { | |
| 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); | |
| return emps; | |
| } | |
| public List<Employee> employeesFetchAddressAndPhonesBatchAndUsingRedirector(EntityManager em) { | |
| 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"); | |
| // Configure redirector so the FetchPlan.fetch is executed automatically | |
| fetchPlan.fetchOnExecute(JpaHelper.getReadAllQuery(query)); | |
| return query.getResultList(); | |
| } | |
| /** | |
| * Simple example retrieving just the firstName and lastName of the | |
| * Employee. This will also include the required identifier and optimistic | |
| * locking values (id and version). | |
| */ | |
| public List<Employee> maleEmployeeCopyNames(EntityManager em) { | |
| FetchPlan fetchPlan = new FetchPlan(Employee.class); | |
| fetchPlan.addAttribute("firstName"); | |
| fetchPlan.addAttribute("lastName"); | |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.gender = :GENDER"); | |
| query.setParameter("GENDER", Gender.Male); | |
| // Configure a dynamic FetchGroup based on the FetchPlan | |
| query.setHint(QueryHints.FETCH_GROUP, fetchPlan.createFetchGroup()); | |
| List<Employee> emps = query.getResultList(); | |
| // This ensures all required relationships are loaded | |
| // In this case it does nothing | |
| JpaFetchPlanHelper.fetch(em, fetchPlan, emps); | |
| // Get a set of copies with only the names and required attributes | |
| // populated | |
| List<Employee> copies = JpaFetchPlanHelper.copy(em, fetchPlan, emps); | |
| return copies; | |
| } | |
| /** | |
| * This example illustrates how a FetchPlan can be constructed based on the | |
| * default fetch configuration of the mappings and used to copy the | |
| * resulting entities. This can be used to create a detached entity graph | |
| * where all EAGER attributes are loaded and all LAZY attributes are | |
| * returned as NULL. | |
| */ | |
| public List<Employee> copyEagerAttributesOnly(EntityManager em) { | |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.firstName IS NOT NULL AND e.lastName IS NOT NULL AND e.salary > 0 "); | |
| // The result of this query is a collection of Employee instances where | |
| // all EAGER attributes are populated and all LAZY attributes are | |
| // available | |
| // for loading with proxy objects (FetchGroup for basics, ValueHolders | |
| // for 1:1 and M:1, and IndirectList/Map/Set for collections). If | |
| // serialized at this point these will not appear as null. | |
| List<Employee> emps = query.getResultList(); | |
| // Create a FetchPlan based on the default FetchGroup | |
| FetchPlan fetchPlan = new FetchPlan(Employee.class); | |
| JpaFetchPlanHelper.addDefaultFetchAttributes(em, fetchPlan); | |
| // Get a set of copies with only the names and required attributes | |
| // populated | |
| List<Employee> copies = JpaFetchPlanHelper.copy(em, fetchPlan, emps); | |
| return copies; | |
| } | |
| /** | |
| * Load all employees's first and last names (plus required id and version) | |
| * attributes based on a FetchGroup and copy the results based on this plan. | |
| */ | |
| public List<Employee> employeeCopyNamesWithFetchGroup(EntityManager em) { | |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.gender IS NOT NULL"); | |
| FetchPlan fetchPlan = new FetchPlan(Employee.class); | |
| fetchPlan.addAttribute("firstName"); | |
| fetchPlan.addAttribute("lastName"); | |
| // Configure a dynamic FetchGroup based on the FetchPlan | |
| query.setHint(QueryHints.FETCH_GROUP, fetchPlan.createFetchGroup()); | |
| List<Employee> emps = query.getResultList(); | |
| return JpaFetchPlanHelper.copy(em, fetchPlan, emps); | |
| } | |
| /** | |
| * Create copies of managed objects requiring relationships that were not | |
| * loaded in the initial query. The copy operation will force the fetching | |
| * of required relationships. | |
| */ | |
| public List<Employee> employeeCopyWithNamesAddressAndPhones(EntityManager em) { | |
| 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); | |
| } | |
| /** | |
| * Create copies of managed objects requiring relationships that were not | |
| * loaded in the initial query. The copy operation will force the fetching | |
| * of required relationships. | |
| */ | |
| public List<Employee> employeeCopyWithNamesAddressAndPhonesWithBatching(EntityManager em) { | |
| 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"); | |
| // Optimize graph loading using batching | |
| query.setHint(QueryHints.BATCH, "e.address"); | |
| query.setHint(QueryHints.BATCH, "e.phoneNumbers"); | |
| List<Employee> emps = query.getResultList(); | |
| return JpaFetchPlanHelper.copy(em, fetchPlan, emps); | |
| } | |
| /** | |
| * Illustrate a multi-level fetch | |
| */ | |
| public List<Employee> managerManagerManagerFetchWithNames(EntityManager em) { | |
| FetchPlan fetchPlan = new FetchPlan(Employee.class); | |
| fetchPlan.addAttribute("firstName"); | |
| fetchPlan.addAttribute("lastName"); | |
| fetchPlan.addAttribute("manager.firstName"); | |
| fetchPlan.addAttribute("manager.lastName"); | |
| fetchPlan.addAttribute("manager.manager.firstName"); | |
| fetchPlan.addAttribute("manager.manager.lastName"); | |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.manager.manager IS NOT NULL"); | |
| List<Employee> emps = query.getResultList(); | |
| JpaFetchPlanHelper.fetch(em, fetchPlan, emps); | |
| return emps; | |
| } | |
| /** | |
| * Example of a composite select returning both an Employee and its count of | |
| * PhoneNumbers. To use the {@link FetchPlan} in this case you must also | |
| * provide the index into the resulting Object[]. | |
| */ | |
| public List<Object[]> employeeAddress_ReturnBoth(EntityManager em) { | |
| FetchPlan fetchPlan = new FetchPlan(Employee.class); | |
| fetchPlan.addAttribute("address"); | |
| fetchPlan.addAttribute("phoneNumbers"); | |
| Query query = em.createQuery("SELECT e, e.address FROM Employee e WHERE e.firstName <> e.lastName"); | |
| List<Object[]> results = query.getResultList(); | |
| JpaFetchPlanHelper.fetch(em, fetchPlan, results, 0); | |
| return results; | |
| } | |
| /** | |
| * Example of using a FetchPlan to retrieve an entity and copy a partial | |
| * unmanaged graph of the entity which is then modified and merged back into | |
| * the persistence context. | |
| * | |
| * Note: caller manages transactions | |
| */ | |
| public void copyMergeExample(EntityManager em, boolean clear) { | |
| FetchPlan fetchPlan = new FetchPlan(Employee.class); | |
| fetchPlan.addAttribute("firstName"); | |
| fetchPlan.addAttribute("lastName"); | |
| fetchPlan.addAttribute("address"); | |
| fetchPlan.addAttribute("phoneNumbers"); | |
| int minId = ((Number) em.createQuery("SELECT MIN(e.id) FROM Employee e").getSingleResult()).intValue(); | |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = " + minId); | |
| query.setHint(QueryHints.FETCH_GROUP, fetchPlan.createFetchGroup()); | |
| Employee emp = (Employee) query.getSingleResult(); | |
| Employee copy = JpaFetchPlanHelper.copy(em, fetchPlan, emp); | |
| copy.setSalary(Integer.MAX_VALUE); | |
| copy.setFirstName(emp.getLastName()); | |
| copy.setLastName(emp.getFirstName()); | |
| JpaFetchPlanHelper.merge(em, fetchPlan, copy); | |
| } | |
| /** | |
| * | |
| */ | |
| public List<Employee> createFetchPlanFromDefaultFetchGroup(EntityManager em) { | |
| FetchPlan fetchPlan = new FetchPlan(Employee.class); | |
| JpaFetchPlanHelper.addDefaultFetchAttributes(em, fetchPlan); | |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.salary > 0"); | |
| query.setHint(QueryHints.FETCH_GROUP, fetchPlan.createFetchGroup()); | |
| List<Employee> emps = query.getResultList(); | |
| JpaFetchPlanHelper.fetch(em, fetchPlan, emps); | |
| return emps; | |
| } | |
| } |