blob: c285131076b88c806ae15bf38b49bc8cf3f7359d [file] [log] [blame]
/*
* 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.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 SimpleNamedFetchGroupTests extends BaseFetchGroupTests {
public SimpleNamedFetchGroupTests() {
super();
}
public SimpleNamedFetchGroupTests(String name) {
super(name);
}
public static junit.framework.Test suite() {
TestSuite suite = new TestSuite();
suite.setName("SimpleNamedFetchGroupTests");
suite.addTest(new SimpleNamedFetchGroupTests("testSetup"));
suite.addTest(new SimpleNamedFetchGroupTests("findDefaultFetchGroup"));
suite.addTest(new SimpleNamedFetchGroupTests("singleResultDefaultFetchGroup"));
suite.addTest(new SimpleNamedFetchGroupTests("resultListDefaultFetchGroup"));
suite.addTest(new SimpleNamedFetchGroupTests("singleResultNoFetchGroup"));
suite.addTest(new SimpleNamedFetchGroupTests("resultListNoFetchGroup"));
suite.addTest(new SimpleNamedFetchGroupTests("managerFetchGroup"));
suite.addTest(new SimpleNamedFetchGroupTests("namedEmptyFetchGroupUsingGetSingleResult"));
suite.addTest(new SimpleNamedFetchGroupTests("namedNamesFetchGroupUsingGetSingleResult"));
suite.addTest(new SimpleNamedFetchGroupTests("joinFetchEmployeeAddressWithDynamicFetchGroup"));
suite.addTest(new SimpleNamedFetchGroupTests("joinFetchEmployeeAddressPhoneWithDynamicFetchGroup"));
return suite;
}
@Override
public void setUp() {
super.setUp();
FetchGroup namedEmpFG = new FetchGroup("Employee.test");
namedEmpFG.addAttribute("firstName");
namedEmpFG.addAttribute("lastName");
employeeDescriptor.getFetchGroupManager().addFetchGroup(namedEmpFG);
FetchGroup namedPhoneFG = new FetchGroup("Phone.test");
namedPhoneFG.addAttribute("number");
phoneDescriptor.getFetchGroupManager().addFetchGroup(namedPhoneFG);
FetchGroup namedAddressFG = new FetchGroup("Address.test");
namedAddressFG.addAttribute("city");
addressDescriptor.getFetchGroupManager().addFetchGroup(namedAddressFG);
assertConfig(employeeDescriptor, null, 1);
assertConfig(phoneDescriptor, null, 1);
assertConfig(addressDescriptor, null, 1);
}
@Test
public void findDefaultFetchGroup() throws Exception {
EntityManager em = createEntityManager();
Employee emp = minimumEmployee(em);
assertNotNull(emp);
assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp);
emp.getSalary();
assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp.getAddress());
assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
for (PhoneNumber phone : emp.getPhoneNumbers()) {
assertNoFetchGroup(phone);
}
int nSqlExpected = 3;
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) {
assertNoFetchGroup(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());
}
}
@Test
public void singleResultDefaultFetchGroup() throws Exception {
EntityManager em = createEntityManager();
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());
assertNoFetchGroup(emp);
emp.getSalary();
assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp.getAddress());
assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
for (PhoneNumber phone : emp.getPhoneNumbers()) {
assertNoFetchGroup(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) {
assertNoFetchGroup(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());
}
}
@Test
public void resultListDefaultFetchGroup() throws Exception {
EntityManager em = createEntityManager();
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);
assertNotNull(emp);
assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp);
emp.getSalary();
assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp.getAddress());
assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
for (PhoneNumber phone : emp.getPhoneNumbers()) {
assertNoFetchGroup(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) {
assertNoFetchGroup(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());
}
}
@Test
public void singleResultNoFetchGroup() throws Exception {
EntityManager em = createEntityManager();
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());
assertNoFetchGroup(emp);
emp.getSalary();
assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp.getAddress());
assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
for (PhoneNumber phone : emp.getPhoneNumbers()) {
assertNoFetchGroup(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) {
assertNoFetchGroup(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());
}
}
@Test
public void resultListNoFetchGroup() throws Exception {
EntityManager em = createEntityManager();
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);
assertNotNull(emp);
assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp);
emp.getSalary();
assertEquals(2, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp.getAddress());
assertEquals(3, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
for (PhoneNumber phone : emp.getPhoneNumbers()) {
assertNoFetchGroup(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) {
assertNoFetchGroup(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());
}
}
@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);
assertNotNull(getFetchGroup(query));
assertSame(managerFG, getFetchGroup(query));
Employee emp = (Employee) query.getSingleResult();
assertFetched(emp, managerFG);
assertEquals(1, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
int nSqlToAdd = 0;
if (emp.getManager() != null) {
assertFetchedAttribute(emp, "manager");
// additional sql to select the manager
nSqlToAdd++;
}
assertEquals(1 + nSqlToAdd, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
// instantiates the whole object
emp.getLastName();
assertEquals(2 + nSqlToAdd, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
assertNoFetchGroup(emp);
for (PhoneNumber phone : emp.getPhoneNumbers()) {
assertNoFetchGroup(phone);
}
assertEquals(3 + nSqlToAdd, getQuerySQLTracker(em).getTotalSQLSELECTCalls());
} finally {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
closeEntityManager(em);
}
}
@Test
public void namedEmptyFetchGroupUsingGetSingleResult() throws Exception {
ClassDescriptor descriptor = getDescriptor("Employee");
FetchGroup fetchGroup = new FetchGroup("test");
descriptor.getFetchGroupManager().addFetchGroup(fetchGroup);
assertTrue(fetchGroup.getItems().isEmpty());
assertEquals(2, descriptor.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);
FetchGroupTracker tracker = (FetchGroupTracker) emp;
assertNotNull(tracker);
FetchGroup usedFG = tracker._persistence_getFetchGroup();
assertNotNull("No FetchGroup found on read Employee", usedFG);
// 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(2, fetchGroup.getItems().size());
assertTrue(tracker._persistence_isAttributeFetched("id"));
assertTrue(tracker._persistence_isAttributeFetched("version"));
assertFalse(tracker._persistence_isAttributeFetched("salary"));
assertFalse(tracker._persistence_isAttributeFetched("firstName"));
assertFalse(tracker._persistence_isAttributeFetched("lastName"));
}
@Test
public void namedNamesFetchGroupUsingGetSingleResult() throws Exception {
ClassDescriptor descriptor = getDescriptor("Employee");
FetchGroup fetchGroup = new FetchGroup("names");
fetchGroup.addAttribute("firstName");
fetchGroup.addAttribute("lastName");
descriptor.getFetchGroupManager().addFetchGroup(fetchGroup);
assertEquals(2, fetchGroup.getItems().size());
assertEquals(2, descriptor.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 FetcGroup found on read Employee", fetchGroup);
// 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"));
}
@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() {
EntityManager em = createEntityManager();
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");
query.setHint(QueryHints.FETCH_GROUP, fetchGroup);
List<Employee> emps = query.getResultList();
assertNotNull(emps);
}
}