| /* |
| * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // 05/19/2010-2.1 ailitchev - Bug 244124 - Add Nested FetchGroup |
| package org.eclipse.persistence.testing.tests.jpa.fetchgroups; |
| |
| import java.util.List; |
| |
| import jakarta.persistence.EntityManager; |
| import jakarta.persistence.Query; |
| |
| import junit.framework.TestSuite; |
| |
| import org.eclipse.persistence.config.DescriptorCustomizer; |
| import org.eclipse.persistence.config.QueryHints; |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.queries.FetchGroup; |
| import org.eclipse.persistence.queries.FetchGroupTracker; |
| import org.eclipse.persistence.testing.models.jpa.advanced.Employee; |
| import org.eclipse.persistence.testing.models.jpa.advanced.PhoneNumber; |
| |
| import org.junit.Test; |
| |
| /** |
| * Simple tests to verify the functionality of single level FetchGroup usage |
| * |
| * @author dclarke |
| * @since EclipseLink 2.1 |
| */ |
| public class SimpleDefaultFetchGroupTests extends BaseFetchGroupTests { |
| |
| public SimpleDefaultFetchGroupTests() { |
| super(); |
| } |
| |
| public SimpleDefaultFetchGroupTests(String name) { |
| super(name); |
| } |
| |
| public static junit.framework.Test suite() { |
| TestSuite suite = new TestSuite(); |
| suite.setName("SimpleDefaultFetchGroupTests"); |
| |
| suite.addTest(new SimpleDefaultFetchGroupTests("testSetup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("findDefaultFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("singleResultDefaultFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("resultListDefaultFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("resultListWithJoinFetchAddress")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("resultListWithJoinFetchAddress_AddressInFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("singleResultNoFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("resultListNoFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("emptyFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("managerFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("employeeNamesFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("namedEmptyFetchGroupUsingGetSingleResult")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("namedNamesFetchGroupUsingGetSingleResult")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("joinFetchEmployeeAddressWithDynamicFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("joinFetchEmployeeAddressPhoneWithDynamicFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("joinFetchEmployeeAddressPhoneWithDynamicFetchGroup_AddressInFetchGroup")); |
| suite.addTest(new SimpleDefaultFetchGroupTests("readThroughServerSession")); |
| |
| return suite; |
| } |
| |
| /** |
| * Set default fetch groups. |
| * |
| * @see EmployeeCustomizer |
| * @see PhoneCustomizer |
| */ |
| @Override |
| public void setUp() { |
| super.setUp(); |
| |
| try { |
| (new EmployeeCustomizer()).customize(employeeDescriptor); |
| (new PhoneCustomizer()).customize(phoneDescriptor); |
| // reprepare read queries after all fetch groups set into all descriptors. |
| reprepareReadQueries(employeeDescriptor); |
| reprepareReadQueries(phoneDescriptor); |
| } catch (RuntimeException rtEx) { |
| throw rtEx; |
| } catch (Exception ex) { |
| throw new RuntimeException(ex); |
| } |
| |
| FetchGroup defaultEmpFG = employeeDescriptor.getDefaultFetchGroup(); |
| FetchGroup defaultPhoneFG = phoneDescriptor.getDefaultFetchGroup(); |
| |
| assertConfig(employeeDescriptor, defaultEmpFG, 0); |
| assertConfig(phoneDescriptor, defaultPhoneFG, 0); |
| |
| } |
| |
| @Test |
| public void findDefaultFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| Employee emp = minimumEmployee(em); |
| assertNotNull(emp); |
| assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertDefaultFetched(emp); |
| |
| assertNotFetchedAttribute(emp, "salary"); |
| emp.getSalary(); |
| |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertFetchedAttribute(emp, "salary"); |
| |
| assertNoFetchGroup(emp.getAddress()); |
| |
| assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| } |
| |
| int nSqlExpected = 4; |
| if (usesSOP()) { |
| // When SOP is used PhoneNumbers are read in sopObject when the fetch group is triggered, so one less sql. |
| nSqlExpected--; |
| } |
| |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| if (emp.getManager() != null) { |
| assertDefaultFetched(emp.getManager()); |
| assertEquals(++nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } else { |
| // If manager_id field is null then getManager() does not trigger an sql. |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void singleResultDefaultFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| |
| Employee emp = (Employee) query.getSingleResult(); |
| |
| assertNotNull(emp); |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| assertDefaultFetched(emp); |
| |
| emp.getSalary(); |
| |
| assertFetchedAttribute(emp, "salary"); |
| assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| assertNoFetchGroup(emp.getAddress()); |
| |
| assertEquals(4, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| } |
| |
| int nSqlExpected = 5; |
| if (usesSOP()) { |
| // When SOP is used PhoneNumbers are read in sopObject when the fetch group is triggered, so one less sql. |
| nSqlExpected--; |
| } |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| if (emp.getManager() != null) { |
| assertDefaultFetched(emp.getManager()); |
| assertEquals(++nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } else { |
| // If manager_id field is null then getManager() does not trigger an sql. |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void resultListDefaultFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| |
| List<Employee> emps = query.getResultList(); |
| |
| assertNotNull(emps); |
| assertEquals(1, emps.size()); |
| |
| Employee emp = emps.get(0); |
| |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertDefaultFetched(emp); |
| |
| emp.getSalary(); |
| |
| assertNoFetchGroup(emp); |
| assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| assertNoFetchGroup(emp.getAddress()); |
| |
| assertEquals(4, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| } |
| int nSqlExpected = 5; |
| if (usesSOP()) { |
| // When SOP is used PhoneNumbers are read in sopObject when the fetch group is triggered, so one less sql. |
| nSqlExpected--; |
| } |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| if (emp.getManager() != null) { |
| assertDefaultFetched(emp.getManager()); |
| assertEquals(++nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } else { |
| // If manager_id field is null then getManager() does not trigger an sql. |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void resultListWithJoinFetchAddress() { |
| internalResultListWithJoinFetchAddress(false); |
| } |
| |
| @Test |
| public void resultListWithJoinFetchAddress_AddressInFetchGroup() { |
| internalResultListWithJoinFetchAddress(true); |
| } |
| void internalResultListWithJoinFetchAddress(boolean addAddressToFetchGroup) { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| Query query = em.createQuery("SELECT e FROM Employee e JOIN FETCH e.address WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| FetchGroup fg = null; |
| if(addAddressToFetchGroup) { |
| // that returns clone of the default fetch group |
| fg = employeeDescriptor.getFetchGroupManager().createDefaultFetchGroup(); |
| fg.addAttribute("address"); |
| query.setHint(QueryHints.FETCH_GROUP, fg); |
| } |
| Employee emp = (Employee)query.getSingleResult(); |
| int nSql = 2; |
| if(!addAddressToFetchGroup) { |
| // An extra sql to read employee's Address - |
| // because address attribute is not in the fetch group the Address object was not built |
| // by join fetch - though the db row for address was read in. |
| // |
| // yet another extra sql generated when the whole employee object is read when address is set. |
| nSql = nSql + 2; |
| } |
| |
| assertEquals(nSql, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| if(addAddressToFetchGroup) { |
| assertFetched(emp, fg); |
| } else { |
| // the whole object has been instantiated when address has been set |
| assertNoFetchGroup(emp); |
| } |
| |
| // instantiates the whole object - unless already instantiated |
| emp.getSalary(); |
| |
| assertNoFetchGroup(emp); |
| if(addAddressToFetchGroup) { |
| nSql++; |
| } |
| assertEquals(nSql, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| assertNoFetchGroup(emp.getAddress()); |
| assertEquals(nSql, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| } |
| if (usesSOP()) { |
| // When SOP is used PhoneNumbers are read in sopObject when the fetch group is triggered, so one less sql. |
| } else { |
| ++nSql; |
| } |
| assertEquals(nSql, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| if (emp.getManager() != null) { |
| assertDefaultFetched(emp.getManager()); |
| assertEquals(++nSql, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } else { |
| // If manager_id field is null then getManager() does not trigger an sql. |
| assertEquals(nSql, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void singleResultNoFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| |
| assertNotNull(employeeDescriptor.getFetchGroupManager().getDefaultFetchGroup()); |
| |
| query.setHint(QueryHints.FETCH_GROUP_DEFAULT, "false"); |
| assertNull(getFetchGroup(query)); |
| |
| Employee emp = (Employee) query.getSingleResult(); |
| |
| assertNotNull(emp); |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertNoFetchGroup(emp); |
| assertNoFetchGroup(emp.getAddress()); |
| |
| assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| } |
| |
| assertEquals(4, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void resultListNoFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| query.setHint(QueryHints.FETCH_GROUP_DEFAULT, "false"); |
| |
| List<Employee> emps = query.getResultList(); |
| |
| assertNotNull(emps); |
| assertEquals(1, emps.size()); |
| |
| Employee emp = emps.get(0); |
| |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| assertNoFetchGroup(emp); |
| assertNoFetchGroup(emp.getAddress()); |
| |
| assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| } |
| assertEquals(4, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void emptyFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| // Use q query since find will only use default fetch group |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| FetchGroup emptyFG = new FetchGroup("empty@" + System.currentTimeMillis()); |
| query.setHint(QueryHints.FETCH_GROUP, emptyFG); |
| |
| assertEquals(emptyFG, getFetchGroup(query)); |
| |
| Employee emp = (Employee) query.getSingleResult(); |
| |
| assertFetched(emp, emptyFG); |
| |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| phone.getAreaCode(); |
| assertNoFetchGroup(phone); |
| } |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Override |
| @Test |
| public void managerFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| //Use q query since find will only use default fetch group |
| //Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| //query.setParameter("ID", minimumEmployeeId(em)); |
| |
| //Complex where clause used to avoid triggering employees and their departments: |
| // Don't include employees who are managers themselves - otherwise if first selected as employee, then as e.manager the full read will be triggered; |
| // Don't include managers with departments - because there is no fetch group on e.manager its (non-null) department will trigger an extra sql |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.manager IS NOT NULL AND NOT EXISTS(SELECT e2 FROM Employee e2 WHERE e2.manager = e) AND e.manager.department IS NULL"); |
| FetchGroup managerFG = new FetchGroup(); |
| managerFG.addAttribute("manager"); |
| |
| query.setHint(QueryHints.FETCH_GROUP, managerFG); |
| query.setHint(QueryHints.LEFT_FETCH, "e.manager"); |
| |
| assertEquals(managerFG, getFetchGroup(query)); |
| |
| List employees = query.getResultList(); |
| Employee emp = (Employee)employees.get(0); |
| |
| assertFetched(emp, managerFG); |
| assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| emp.getManager(); |
| |
| assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertFetched(emp, managerFG); |
| |
| emp.getLastName(); |
| |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertNoFetchGroup(emp); |
| |
| int numPhones = 0; |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| |
| phone.getAreaCode(); |
| |
| assertNoFetchGroup(phone); |
| numPhones++; |
| } |
| // 1 sql to read all the phones with a fetch group + 1 sql per phone to re-read each phone without fetch group |
| int nSqlExpected = 3 + numPhones; |
| if (usesSOP()) { |
| // When SOP is used PhoneNumbers are read in sopObject when the fetch group is triggered, so one less sql. |
| nSqlExpected--; |
| } |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Override |
| @Test |
| public void employeeNamesFetchGroup() throws Exception { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| int minId = minimumEmployeeId(em); |
| assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| // Use q query since find will only use default fetch group |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minId); |
| |
| FetchGroup namesFG = new FetchGroup(); |
| namesFG.addAttribute("firstName"); |
| namesFG.addAttribute("lastName"); |
| query.setHint(QueryHints.FETCH_GROUP, namesFG); |
| |
| assertNotNull(getFetchGroup(query)); |
| assertSame(namesFG, getFetchGroup(query)); |
| |
| Employee emp = (Employee) query.getSingleResult(); |
| |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertFetched(emp, namesFG); |
| |
| emp.getId(); |
| emp.getFirstName(); |
| emp.getLastName(); |
| emp.getVersion(); |
| |
| assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertFetched(emp, namesFG); |
| |
| emp.getGender(); |
| emp.getSalary(); |
| |
| assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertNoFetchGroup(emp); |
| |
| int numPhones = 0; |
| for (PhoneNumber phone : emp.getPhoneNumbers()) { |
| assertDefaultFetched(phone); |
| |
| phone.getAreaCode(); |
| |
| assertNoFetchGroup(phone); |
| numPhones++; |
| } |
| // 1 sql to read all the phones with a fetch group + 1 sql per phone to re-read each phone without fetch group |
| int nSqlExpected = 4 + numPhones; |
| if (usesSOP()) { |
| // When SOP is used PhoneNumbers are read in sopObject when the fetch group is triggered, so one less sql. |
| nSqlExpected--; |
| } |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| |
| if(emp.getManager() != null) { |
| assertEquals(++nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| assertDefaultFetched(emp.getManager()); |
| } else { |
| // If manager_id field is null then getManager() does not trigger an sql. |
| assertEquals(nSqlExpected, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void namedEmptyFetchGroupUsingGetSingleResult() throws Exception { |
| FetchGroup fetchGroup = new FetchGroup("test"); |
| employeeDescriptor.getFetchGroupManager().addFetchGroup(fetchGroup); |
| assertTrue(fetchGroup.getItems().isEmpty()); |
| assertEquals(1, employeeDescriptor.getFetchGroupManager().getFetchGroups().size()); |
| |
| EntityManager em = createEntityManager(); |
| |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| query.setHint(QueryHints.FETCH_GROUP_NAME, "test"); |
| |
| Employee emp = (Employee) query.getSingleResult(); |
| assertNotNull(emp); |
| assertFetched(emp, "test"); |
| } |
| |
| @Test |
| public void namedNamesFetchGroupUsingGetSingleResult() throws Exception { |
| FetchGroup fetchGroup = new FetchGroup("names"); |
| fetchGroup.addAttribute("firstName"); |
| fetchGroup.addAttribute("lastName"); |
| |
| employeeDescriptor.getFetchGroupManager().addFetchGroup(fetchGroup); |
| assertEquals(2, fetchGroup.getItems().size()); |
| |
| assertEquals(1, employeeDescriptor.getFetchGroupManager().getFetchGroups().size()); |
| |
| EntityManager em = createEntityManager(); |
| |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.id = :ID"); |
| query.setParameter("ID", minimumEmployeeId(em)); |
| query.setHint(QueryHints.FETCH_GROUP_NAME, "names"); |
| |
| Employee emp = (Employee) query.getSingleResult(); |
| assertNotNull(emp); |
| |
| FetchGroupTracker tracker = (FetchGroupTracker) emp; |
| assertNotNull(tracker); |
| |
| FetchGroup usedFG = tracker._persistence_getFetchGroup(); |
| |
| assertNotNull("No FetchGroup found on read Employee", fetchGroup); |
| // No longer can make any assumptions about a name of FetchGroup on the entity |
| // What's guaranteed is that attribute sets are the same |
| assertTrue(fetchGroup.getAttributeNames().equals(usedFG.getAttributeNames())); |
| // assertEquals(fetchGroup.getName(), usedFG.getName()); |
| // assertSame(fetchGroup, ((EntityFetchGroup)usedFG).getParent()); |
| assertEquals(4, fetchGroup.getItems().size()); |
| assertTrue(tracker._persistence_isAttributeFetched("id")); |
| assertTrue(tracker._persistence_isAttributeFetched("version")); |
| assertFalse(tracker._persistence_isAttributeFetched("salary")); |
| assertTrue(tracker._persistence_isAttributeFetched("firstName")); |
| assertTrue(tracker._persistence_isAttributeFetched("lastName")); |
| assertFalse(tracker._persistence_isAttributeFetched("department")); |
| } |
| |
| @Override |
| @Test |
| public void joinFetchEmployeeAddressWithDynamicFetchGroup() { |
| EntityManager em = createEntityManager(); |
| |
| Query query = em.createQuery("SELECT e FROM Employee e JOIN FETCH e.address"); |
| |
| FetchGroup fetchGroup = new FetchGroup("names"); |
| fetchGroup.addAttribute("firstName"); |
| fetchGroup.addAttribute("lastName"); |
| query.setHint(QueryHints.FETCH_GROUP, fetchGroup); |
| |
| List<Employee> emps = query.getResultList(); |
| |
| assertNotNull(emps); |
| } |
| |
| @Override |
| @Test |
| public void joinFetchEmployeeAddressPhoneWithDynamicFetchGroup() { |
| internalJoinFetchEmployeeAddressPhoneWithDynamicFetchGroup(false); |
| } |
| @Test |
| public void joinFetchEmployeeAddressPhoneWithDynamicFetchGroup_AddressInFetchGroup() { |
| internalJoinFetchEmployeeAddressPhoneWithDynamicFetchGroup(true); |
| } |
| void internalJoinFetchEmployeeAddressPhoneWithDynamicFetchGroup(boolean addAddressToFetchGroup) { |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| |
| Query query = em.createQuery("SELECT e FROM Employee e JOIN FETCH e.address WHERE e.id IN (SELECT p.id FROM PhoneNumber p)"); |
| |
| FetchGroup fetchGroup = new FetchGroup("names"); |
| fetchGroup.addAttribute("firstName"); |
| fetchGroup.addAttribute("lastName"); |
| if(addAddressToFetchGroup) { |
| fetchGroup.addAttribute("address"); |
| } |
| query.setHint(QueryHints.FETCH_GROUP, fetchGroup); |
| |
| List<Employee> emps = query.getResultList(); |
| assertNotNull(emps); |
| |
| if(addAddressToFetchGroup) { |
| assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } else { |
| assertEquals(1 + 2*emps.size(), getQuerySQLTracker(em).getTotalSQLSELECTCalls()); |
| } |
| for (Employee emp : emps) { |
| if(addAddressToFetchGroup) { |
| assertFetched(emp, fetchGroup); |
| } else { |
| // the whole object has been instantiated when address has been set |
| assertNoFetchGroup(emp); |
| } |
| } |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| } |
| |
| @Test |
| public void readThroughServerSession() { |
| List<Employee> emps = null; |
| EntityManager em = createEntityManager(); |
| try { |
| beginTransaction(em); |
| Query query = em.createQuery("SELECT e FROM Employee e WHERE e.address IS NOT NULL"); |
| |
| emps = query.getResultList(); |
| assertNotNull(emps); |
| } finally { |
| if (isTransactionActive(em)){ |
| rollbackTransaction(em); |
| } |
| closeEntityManager(em); |
| } |
| |
| EntityManager em2 = createEntityManager(); |
| try { |
| beginTransaction(em2); |
| em2.flush(); |
| Query query = em2.createQuery("SELECT e FROM Employee e WHERE e.address IS NOT NULL"); |
| emps = query.getResultList(); |
| Employee emp = emps.get(0); |
| emp.getAddress().setCountry("newCountry"); |
| commitTransaction(em2); |
| } finally { |
| if (isTransactionActive(em2)){ |
| rollbackTransaction(em2); |
| } |
| closeEntityManager(em2); |
| } |
| } |
| |
| public static class EmployeeCustomizer implements DescriptorCustomizer { |
| |
| @Override |
| public void customize(ClassDescriptor descriptor) throws Exception { |
| FetchGroup fg = new FetchGroup("Employee-default"); |
| fg.addAttribute("firstName"); |
| fg.addAttribute("lastName"); |
| descriptor.getFetchGroupManager().setDefaultFetchGroup(fg); |
| } |
| |
| } |
| |
| /* public static class PhoneCustomizer implements DescriptorCustomizer { |
| |
| public void customize(ClassDescriptor descriptor) throws Exception { |
| FetchGroup fg = new FetchGroup("Phone-default"); |
| fg.addAttribute("number"); |
| if (!descriptor.hasFetchGroupManager()) { |
| descriptor.setFetchGroupManager(new FetchGroupManager()); |
| } |
| descriptor.getFetchGroupManager().setDefaultFetchGroup(fg); |
| } |
| |
| }*/ |
| } |