Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[master] Clone batchQuery to allow for proper nested lazy instantiation #2367

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -645,7 +645,11 @@ public Object extractResultFromBatchQuery(ReadQuery batchQuery, CacheKey parentC
} else if (batchQuery.isReadAllQuery() && ((ReadAllQuery)batchQuery).getBatchFetchPolicy().isIN()) {
throw QueryException.originalQueryMustUseBatchIN(this, originalQuery);
}
executeBatchQuery(batchQuery, parentCacheKey, batchedObjects, session, translationRow);
// Execute each batch as a separate query so that nested batch relationships are not overwritten by the most
// recent batch fetched Issue #1998
ReadQuery batchQueryToExecute = (ReadQuery) batchQuery.clone();
executeBatchQuery(batchQueryToExecute, parentCacheKey, batchedObjects, session, translationRow);
batchQueryToExecute.setSession(null);
batchQuery.setSession(null);
}
result = batchedObjects.get(sourceKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2025 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:

package org.eclipse.persistence.testing.models.jpa.batchfetch;

import org.eclipse.persistence.tools.schemaframework.FieldDefinition;
import org.eclipse.persistence.tools.schemaframework.TableCreator;
import org.eclipse.persistence.tools.schemaframework.TableDefinition;

public class BatchFetchCacheTableCreator extends TableCreator {
public BatchFetchCacheTableCreator() {
setName("BatchFetchCacheProject");

addTableDefinition(buildParentTable());
addTableDefinition(buildChildTable());
}

public TableDefinition buildParentTable() {
TableDefinition table = new TableDefinition();
table.setName("BATCH_IN_CACHE_PARENT");

FieldDefinition fieldID = new FieldDefinition();
fieldID.setName("ID");
fieldID.setTypeName("NUMBER");
fieldID.setSize(19);
fieldID.setSubSize(0);
fieldID.setIsPrimaryKey(true);
fieldID.setIsIdentity(true);
fieldID.setShouldAllowNull(false);
table.addField(fieldID);

return table;
}


public TableDefinition buildChildTable() {
TableDefinition table = new TableDefinition();
table.setName("BATCH_IN_CACHE_CHILD");

FieldDefinition fieldID = new FieldDefinition();
fieldID.setName("ID");
fieldID.setTypeName("NUMBER");
fieldID.setSize(19);
fieldID.setSubSize(0);
fieldID.setIsPrimaryKey(true);
fieldID.setIsIdentity(true);
fieldID.setShouldAllowNull(false);
table.addField(fieldID);

FieldDefinition fieldParent = new FieldDefinition();
fieldParent.setName("PARENT_ID");
fieldParent.setTypeName("NUMBER");
fieldParent.setSize(19);
fieldParent.setSubSize(0);
fieldParent.setIsPrimaryKey(false);
fieldParent.setIsIdentity(false);
fieldParent.setShouldAllowNull(false);
fieldParent.setForeignKeyFieldName("BATCH_IN_CACHE_PARENT.ID");
table.addField(fieldParent);

return table;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2025 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:

package org.eclipse.persistence.testing.models.jpa.batchfetch;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import org.eclipse.persistence.annotations.BatchFetch;
import org.eclipse.persistence.annotations.BatchFetchType;

@Entity
@Table(name = "BATCH_IN_CACHE_CHILD")
public class Child {
@Id
@GeneratedValue
private long id;

@ManyToOne
@JoinColumn(name = "PARENT_ID")
@BatchFetch(value = BatchFetchType.IN)
private Parent parent;

public Child() {
}

public Child(long id, Parent parent) {
this.id = id;
this.parent = parent;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public Parent getParent() {
return parent;
}

public void setParent(Parent parent) {
this.parent = parent;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2025 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:

package org.eclipse.persistence.testing.models.jpa.batchfetch;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.eclipse.persistence.annotations.BatchFetch;
import org.eclipse.persistence.annotations.BatchFetchType;
import org.eclipse.persistence.annotations.CascadeOnDelete;

import java.util.Collection;

@Entity
@Table(name = "BATCH_IN_CACHE_PARENT")
public class Parent {
@Id
@GeneratedValue
private long id;

@OneToMany(mappedBy = "parent")
@BatchFetch(value = BatchFetchType.IN)
private Collection<Child> children;

public Parent() {
}

public Parent(long id) {
this.id = id;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public Collection<Child> getChildren() {
return children;
}

public void setChildren(Collection<Child> children) {
this.children = children;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!--

Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2024, 2025 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
Expand All @@ -20,6 +20,8 @@
<class>org.eclipse.persistence.testing.models.jpa.batchfetch.Company</class>
<class>org.eclipse.persistence.testing.models.jpa.batchfetch.Employee</class>
<class>org.eclipse.persistence.testing.models.jpa.batchfetch.Record</class>
<class>org.eclipse.persistence.testing.models.jpa.batchfetch.Child</class>
<class>org.eclipse.persistence.testing.models.jpa.batchfetch.Parent</class>
<properties>
<property name="eclipselink.logging.level" value="${eclipselink.logging.level}"/>
<property name="eclipselink.logging.level.sql" value="${eclipselink.logging.sql.level}"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright (c) 1998, 2025 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:

package org.eclipse.persistence.testing.tests.jpa.batchfetch;

import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.testing.framework.jpa.junit.JUnitTestCase;
import org.eclipse.persistence.testing.models.jpa.batchfetch.BatchFetchCacheTableCreator;
import org.eclipse.persistence.testing.models.jpa.batchfetch.Child;
import org.eclipse.persistence.testing.models.jpa.batchfetch.Parent;

import java.util.Collection;
import java.util.List;
import java.util.Objects;

public class BatchFetchCacheJUnitTest extends JUnitTestCase {

public BatchFetchCacheJUnitTest() {
super();
}

public BatchFetchCacheJUnitTest(String name) {
super(name);
}

public static Test suite() {
TestSuite suite = new TestSuite();
suite.setName("BatchFetchCacheJunitTest");
suite.addTest(new BatchFetchCacheJUnitTest("testSetup"));
suite.addTest(new BatchFetchCacheJUnitTest("testSelectChildren"));
return suite;
}

/**
* The setup is done as a test, both to record its failure, and to allow execution in the server.
*/
public void testSetup() {
new BatchFetchCacheTableCreator().replaceTables(JUnitTestCase.getServerSession(
getPersistenceUnitName()));
EntityManager em = createEntityManager();
createRecords(em);
}

public void createRecords(EntityManager em) {
try {
beginTransaction(em);
Parent p1 = new Parent(1);
Parent p2 = new Parent(2);
Parent p3 = new Parent(3);
em.persist(p1);
em.persist(p2);
em.persist(p3);

Child u1 = new Child(1, p1);
Child u2 = new Child(2, p2);
Child u3 = new Child(3, p3);
em.persist(u1);
em.persist(u2);
em.persist(u3);

commitTransaction(em);
} catch (RuntimeException ex) {
if (isTransactionActive(em)) {
rollbackTransaction(em);
}
throw ex;
} finally {
closeEntityManager(em);
}
}

public void testSelectChildren() {
EntityManager em = createEntityManager();
em.getEntityManagerFactory().getCache().evictAll();

try {
TypedQuery<Child> q = em.createQuery("SELECT c FROM Child c", Child.class);
q.setHint(QueryHints.BATCH_SIZE, 1);
List<Child> result = q.getResultList();
assertEquals("Not all rows are selected", 3, result.size());
List<Parent> parents = result.stream().map(Child::getParent).filter(Objects::nonNull).toList();
assertEquals("Not all rows have parents", 3, parents.size());
List<Child> childrenOfParents = parents.stream()
.map(Parent::getChildren)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.toList();
assertEquals("Not all parents have children", 3, childrenOfParents.size());
} catch (RuntimeException e) {
closeEntityManager(em);
throw e;
}
}

@Override
public String getPersistenceUnitName() {
return "batchfetch";
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025 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
Expand Down Expand Up @@ -54,7 +54,7 @@ public static Test suite() {
*/
public void testSetup() {
new BatchFetchTableCreator().replaceTables(JUnitTestCase.getServerSession(
"batchfetch"));
getPersistenceUnitName()));
EntityManager em = createEntityManager();
createRecords(em);
}
Expand Down
Loading