/******************************************************************************* | |
* 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 test; | |
import static org.junit.Assert.*; | |
import java.util.ArrayList; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Set; | |
import javax.persistence.EntityManager; | |
import javax.persistence.PersistenceContext; | |
import javax.persistence.Query; | |
import model.Address; | |
import model.Employee; | |
import model.SmallProject; | |
import org.eclipse.persistence.config.QueryHints; | |
import org.eclipse.persistence.extension.fetchplan.FetchPlan; | |
import org.eclipse.persistence.extension.fetchplan.JpaFetchPlanHelper; | |
import org.eclipse.persistence.extension.query.BatchInConfig; | |
import org.eclipse.persistence.jpa.JpaHelper; | |
import org.junit.After; | |
import org.junit.Test; | |
import test.fetchplan.FetchPlanAssert; | |
import testing.EclipseLinkJPATest; | |
/** | |
* | |
* @author dclarke | |
* @since EclipseLink 1.2 | |
*/ | |
@PersistenceContext(unitName = "employee") | |
public class FetchPlanFetchWithBatchInTests extends EclipseLinkJPATest { | |
@SuppressWarnings("unchecked") | |
@Test | |
public void fetchAddressAndPhones() { | |
EntityManager em = getEntityManager(); | |
FetchPlan plan = new FetchPlan(Employee.class); | |
plan.addAttribute("address"); | |
plan.addAttribute("phoneNumbers"); | |
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.salary > 0.0"); | |
query.setHint(QueryHints.BATCH, "e.address"); | |
query.setHint(QueryHints.BATCH, "e.phoneNumbers"); | |
List<Employee> emps = query.getResultList(); | |
BatchInConfig.config(em, emps, "address"); | |
BatchInConfig.config(em, emps, "phoneNumbers"); | |
JpaFetchPlanHelper.fetch(em, plan, emps); | |
} | |
@SuppressWarnings("unchecked") | |
@Test | |
public void fetchManagerManager() { | |
EntityManager em = getEntityManager(); | |
FetchPlan plan = new FetchPlan(Employee.class); | |
plan.addAttribute("managedEmployees.managedEmployees"); | |
Query query = em.createQuery("SELECT e FROM Employee e WHERE e.managedEmployees IS NOT EMPTY"); | |
query.setHint(QueryHints.BATCH, "e.managedEmployees"); | |
query.setHint(QueryHints.BATCH, "e.managedEmployees.managedEmployees"); | |
List<Employee> emps = query.getResultList(); | |
BatchInConfig.config(em, emps, "managedEmployees"); | |
BatchInConfig.config(em, emps.get(0).getManagedEmployees(), "managedEmployees"); | |
JpaFetchPlanHelper.fetch(em, plan, emps); | |
for (Employee emp : emps) { | |
System.out.println("> " + emp); | |
for (Employee me : emp.getManagedEmployees()) { | |
System.out.println("\t> " + me); | |
for (Employee me2 : me.getManagedEmployees()) { | |
System.out.println("\t\t> " + me2); | |
} | |
} | |
} | |
assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); | |
} | |
/** | |
* In this test we only try to select all small projects and fetch their | |
* teamleaders. Somehow a strange sql gets created and a database exception | |
* occurs. | |
*/ | |
@Test | |
public void findSmallProjectsWithBatchInConfigFetch() { | |
EntityManager em = getEntityManager(); | |
em.getTransaction().begin(); | |
Query q = em.createQuery("SELECT sm FROM SmallProject sm"); | |
q.setHint(QueryHints.BATCH, "sm.teamLeader"); | |
List<SmallProject> sms = q.getResultList(); | |
BatchInConfig.config(em, sms, "teamLeader"); | |
FetchPlan fp = new FetchPlan(SmallProject.class); | |
fp.addAttribute("teamLeader"); | |
JpaFetchPlanHelper.fetch(em, fp, sms); | |
// Here comes Exception | |
em.getTransaction().rollback(); | |
} | |
/** | |
* In this test, we select all employees with their managed employees and | |
* their addresses. Because of unknown reason, we get a | |
* IllegalArgumentException on the second call to BatchInConfig.config. The | |
* BatchValueHolder should not be set. But we have set the batch hint. So | |
* whats wrong? | |
*/ | |
@SuppressWarnings("unchecked") | |
@Test | |
public void findEmployeesWithBatchInConfigFetch() { | |
EntityManager em = getEntityManager(); | |
Query q = em.createQuery("SELECT em FROM Employee em ORDER BY em.id"); | |
q.setHint(QueryHints.BATCH, "em.managedEmployees"); | |
q.setHint(QueryHints.BATCH, "em.managedEmployees.address"); | |
List<Employee> ems = q.getResultList(); | |
// Display initial Employees read: | |
System.out.println("Employees Read - " + ems.size()); | |
for (Employee emp : ems) { | |
System.out.println("\t> " + emp); | |
} | |
BatchInConfig.config(em, ems, "managedEmployees"); | |
FetchPlan fp = new FetchPlan(Employee.class); | |
fp.addAttribute("managedEmployees"); | |
JpaFetchPlanHelper.fetch(em, fp, ems); | |
// iterate through all employees and collect their managers | |
Set<Employee> managedEmployees = new HashSet<Employee>(); | |
for (Employee employee : ems) { | |
managedEmployees.addAll(employee.getManagedEmployees()); | |
} | |
// Fetch for all managers the addresses | |
BatchInConfig.config(em, new ArrayList<Employee>(managedEmployees), "address"); | |
FetchPlan fp2 = new FetchPlan(Employee.class); | |
fp2.addAttribute("address"); | |
JpaFetchPlanHelper.fetch(em, fp2, managedEmployees); | |
assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); | |
System.out.println("Employees Read - " + ems.size()); | |
for (Employee emp : ems) { | |
System.out.println("\t> " + emp); | |
for (Employee managedEmp : emp.getManagedEmployees()) { | |
System.out.println("\t\t> " + managedEmp); | |
System.out.println("\t\t\t> " + managedEmp.getAddress()); | |
} | |
if (emp.getManagedEmployees() == null) { | |
} | |
} | |
assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); | |
em.clear(); | |
JpaHelper.getServerSession(getEMF()).getIdentityMapAccessor().initializeAllIdentityMaps(); | |
q = em.createNativeQuery("SELECT EMP_ID, ADDR_ID, MANAGER_ID FROM EMPLOYEE ORDER BY EMP_ID"); | |
List<Object[]> ids = q.getResultList(); | |
assertEquals(4, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); | |
assertEquals(ems.size(), ids.size()); | |
for (int index = 0; index < ems.size(); index++) { | |
Employee emp = ems.get(index); | |
Object[] idRow = ids.get(index); | |
assertEquals(emp.getId(), ((Number) idRow[0]).intValue()); | |
if (idRow[2] != null) { // We have a manager | |
assertNotNull(emp.getAddress()); | |
assertEquals(emp.getAddress().getId(), ((Number) idRow[1]).intValue()); | |
} else { | |
} | |
} | |
} | |
/** | |
* This test does not used BatchIn but is here to provide a verification for | |
* the assertions of {@link #findEmployeesWithBatchInConfigFetch()} | |
*/ | |
@SuppressWarnings("unchecked") | |
@Test | |
public void findEmployeesWithJoinBatching() { | |
EntityManager em = getEntityManager(); | |
Query q = em.createQuery("SELECT em FROM Employee em ORDER BY em.id"); | |
q.setHint(QueryHints.BATCH, "em.managedEmployees"); | |
q.setHint(QueryHints.BATCH, "em.managedEmployees.address"); | |
List<Employee> ems = q.getResultList(); | |
// Display initial Employees read: | |
System.out.println("Employees Read - " + ems.size()); | |
for (Employee emp : ems) { | |
System.out.println("\t> " + emp); | |
} | |
//BatchInConfig.config(em, ems, "managedEmployees"); | |
FetchPlan fp = new FetchPlan(Employee.class); | |
fp.addAttribute("managedEmployees"); | |
JpaFetchPlanHelper.fetch(em, fp, ems); | |
// iterate through all employees and collect their managers | |
Set<Employee> managedEmployees = new HashSet<Employee>(); | |
for (Employee employee : ems) { | |
managedEmployees.addAll(employee.getManagedEmployees()); | |
} | |
// Fetch for all managers the addresses | |
//BatchInConfig.config(em, new ArrayList<Employee>(managedEmployees), "address"); | |
FetchPlan fp2 = new FetchPlan(Employee.class); | |
fp2.addAttribute("address"); | |
JpaFetchPlanHelper.fetch(em, fp2, managedEmployees); | |
assertEquals(13, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); | |
System.out.println("Employees Read - " + ems.size()); | |
for (Employee emp : ems) { | |
System.out.println("\t> " + emp); | |
for (Employee managedEmp : emp.getManagedEmployees()) { | |
System.out.println("\t\t> " + managedEmp); | |
System.out.println("\t\t\t> " + managedEmp.getAddress()); | |
} | |
if (emp.getManagedEmployees() == null) { | |
} | |
} | |
assertEquals(13, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); | |
em.clear(); | |
JpaHelper.getServerSession(getEMF()).getIdentityMapAccessor().initializeAllIdentityMaps(); | |
q = em.createNativeQuery("SELECT e.EMP_ID, e.ADDR_ID, e.MANAGER_ID FROM EMPLOYEE e, SALARY s WHERE s.EMP_ID = e.EMP_ID ORDER BY e.EMP_ID"); | |
List<Object[]> ids = q.getResultList(); | |
assertEquals(14, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); | |
assertEquals(ems.size(), ids.size()); | |
for (int index = 0; index < ems.size(); index++) { | |
Employee emp = ems.get(index); | |
Object[] idRow = ids.get(index); | |
assertEquals(emp.getId(), ((Number) idRow[0]).intValue()); | |
if (idRow[2] != null) { // We have a manager | |
assertNotNull(emp.getAddress()); | |
assertEquals("Incorrect address on: " + emp, emp.getAddress().getId(), ((Number) idRow[1]).intValue()); | |
} else { | |
} | |
} | |
} | |
/** | |
* Here we just want to show that in the merge SQLs are fired which we | |
* consider unnecessary. | |
* | |
* @throws Exception | |
*/ | |
@Test | |
public void findEmployeesWithBatchInConfigFetchAndDetachThem() throws Exception { | |
EntityManager em = getEntityManager(); | |
em.getTransaction().begin(); | |
Query q = em.createQuery("SELECT em FROM Employee em"); | |
q.setHint(QueryHints.BATCH, "em.managedEmployees"); | |
List<Employee> ems = q.getResultList(); | |
BatchInConfig.config(em, ems, "managedEmployees"); | |
FetchPlan fp = new FetchPlan(Employee.class); | |
fp.addAttribute("managedEmployees"); | |
JpaFetchPlanHelper.fetch(em, fp, ems); | |
// Employee deserializedEmployee = | |
// (Employee)SerializationHelper.clone(ems.get(0)); | |
// Hier clone statt copy führt im merge zu | |
// anderem Ergebnis. | |
Employee deserializedEmployee = JpaFetchPlanHelper.copy(em, new FetchPlan(Employee.class), ems.get(0)); | |
em.getTransaction().commit(); | |
closeEMF(); | |
super.cleanupClosedEMF(); | |
em = getEntityManager(); | |
System.out.println(deserializedEmployee.getAddress());// Would throw | |
// exception, | |
// because | |
// relation not instantiated. But only on clone object. On copied | |
// object, null is returned. | |
em.getTransaction().begin(); | |
deserializedEmployee.setFirstName(deserializedEmployee.getFirstName() + "x"); | |
Employee mergedEmployee = getEntityManager().merge(deserializedEmployee); | |
Address address = mergedEmployee.getAddress(); | |
System.out.println(mergedEmployee.getAddress()); | |
em.getTransaction().commit(); | |
} | |
@After | |
public void clearCache() { | |
JpaHelper.getServerSession(getEMF()).getIdentityMapAccessor().initializeAllIdentityMaps(); | |
} | |
@Override | |
protected void verifyConfig(EntityManager em) { | |
super.verifyConfig(em); | |
FetchPlanAssert.verifyEmployeeConfig(getEMF()); | |
} | |
} |