Skip to content

Commit

Permalink
Update JPQL queries for Embeddables don't include all fields - bugfix…
Browse files Browse the repository at this point in the history
… and unit test (eclipse-ee4j#2345)

* Update JPQL queries for Embeddables don't include all fields - bugfix and unit test

Signed-off-by: Radek Felcman <[email protected]>
  • Loading branch information
rfelcman authored Jan 22, 2025
1 parent 3aee10d commit f2eb9b5
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 5 deletions.
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) 2022 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -239,7 +239,11 @@ public Object getValue(AbstractRecord translationRow, DatabaseQuery query, Abstr
ClassDescriptor descriptor = session.getDescriptor(value);
//Bug4924639 Aggregate descriptors have to be acquired from their mapping as they are cloned and initialized by each mapping
if (descriptor != null && descriptor.isAggregateDescriptor() && ((ParameterExpression)getBaseExpression()).getLocalBase().isObjectExpression()) {
descriptor = ((ObjectExpression)((ParameterExpression)getBaseExpression()).getLocalBase()).getDescriptor();
if (getLocalBase() != null && getLocalBase().isQueryKeyExpression()) {
descriptor = ((QueryKeyExpression)getLocalBase()).getMapping().getDescriptor();
} else {
descriptor = ((ObjectExpression) ((ParameterExpression) getBaseExpression()).getLocalBase()).getDescriptor();
}
}

if (descriptor == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 IBM and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025 IBM 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 @@ -57,6 +57,7 @@
import org.eclipse.persistence.internal.helper.InvalidObject;
import org.eclipse.persistence.internal.helper.NonSynchronizedVector;
import org.eclipse.persistence.internal.identitymaps.CacheKey;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
Expand Down Expand Up @@ -2030,6 +2031,31 @@ public void prepareUpdateAll() {
}
baseExpressions.add(new FieldExpression(fields.get(i), ((QueryKeyExpression)baseExpression).getBaseExpression()));
}
} else if (mapping != null && mapping.isAggregateMapping() && isValueObjectEmbeddableAndParameter(valueObject)) {
fields = mapping.getFields();
int fieldsSize = fields.size();
values = new ArrayList<>(fieldsSize);
baseExpressions = new ArrayList<>(fieldsSize);
for(DatabaseMapping databaseMapping: mapping.getReferenceDescriptor().getMappings()) {
String aName = databaseMapping.getAttributeName();
Expression attributeBaseExpression = baseExpression.get(aName);
baseExpressions.add(attributeBaseExpression);
ParameterExpression exp = (ParameterExpression) ((ParameterExpression)valueObject).clone().getField(new DatabaseField(aName));
builder.setSession(getSession());
if (baseExpression.isQueryKeyExpression()) {
//It will set mapping if it was not initialized before
((QueryKeyExpression)baseExpression).getMapping();
}
if (attributeBaseExpression.isQueryKeyExpression()) {
//It will set mapping if it was not initialized before
((QueryKeyExpression)attributeBaseExpression).getMapping();
}

exp.setLocalBase(attributeBaseExpression);
exp.getBaseExpression().setLocalBase(((ParameterExpression)valueObject).getLocalBase());

values.add(exp);
}
} else {
fields = new ArrayList<>(1);
fields.add(field);
Expand Down Expand Up @@ -2921,4 +2947,14 @@ protected ClassDescriptor getHighestDescriptorMappingTable(DatabaseTable table)
}
return desc;
}

private boolean isValueObjectEmbeddableAndParameter(Object valueObject) {
if (valueObject instanceof ParameterExpression) {
Class type = (Class) ((ParameterExpression)valueObject).getType();
if (getSession().getDescriptor(type) != null) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2022 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 All @@ -25,9 +25,12 @@
import org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator;
import org.eclipse.persistence.testing.models.jpa.advanced.Employee;
import org.eclipse.persistence.testing.models.jpa.advanced.EmployeePopulator;
import org.eclipse.persistence.testing.models.jpa.advanced.EmploymentPeriod;
import org.eclipse.persistence.testing.tests.jpa.jpql.JUnitDomainObjectComparer;

import java.time.LocalDate;
import java.util.Calendar;
import java.util.List;

/**
* <p>
Expand Down Expand Up @@ -99,6 +102,8 @@ public static Test suite()
suite.addTest(new JUnitJPQLModifyTest("simpleUpdate"));
suite.addTest(new JUnitJPQLModifyTest("updateWithSubquery"));
suite.addTest(new JUnitJPQLModifyTest("updateEmbedded"));
suite.addTest(new JUnitJPQLModifyTest("updateEmbeddedObjectWithValue"));
suite.addTest(new JUnitJPQLModifyTest("updateEmbeddedObjectWithNull"));
suite.addTest(new JUnitJPQLModifyTest("updateEmbeddedFieldTest"));
suite.addTest(new JUnitJPQLModifyTest("updateUnqualifiedAttributeInSet"));
suite.addTest(new JUnitJPQLModifyTest("updateUnqualifiedAttributeInWhere"));
Expand Down Expand Up @@ -219,6 +224,78 @@ public void updateEmbedded()
}
}

public void updateEmbeddedObjectWithValue()
{
if ((getPersistenceUnitServerSession()).getPlatform().isSymfoware()) {
getPersistenceUnitServerSession().logMessage("Test updateEmbedded skipped for this platform, "
+ "Symfoware doesn't support UpdateAll/DeleteAll on multi-table objects (see rfe 298193).");
return;
}
EntityManager em = createEntityManager();

long nrOfEmps = executeJPQLReturningInt(
em, "SELECT COUNT(e) FROM Employee e");

// test query
EmploymentPeriod employmentPeriod = new EmploymentPeriod(java.sql.Date.valueOf(LocalDate.of(2020, 1, 1)), java.sql.Date.valueOf(LocalDate.of(2025, 12, 31)));
String update = "UPDATE Employee e SET e.period = ?1";
beginTransaction(em);
try {
Query updateQuery = em.createQuery(update);
updateQuery.setParameter(1, employmentPeriod);
int updated = updateQuery.executeUpdate();
assertEquals("updateEmbedded: wrong number of updated instances",
nrOfEmps, updated);
commitTransaction(em);

// check database changes
Query selectQuery = em.createQuery("SELECT COUNT(e) FROM Employee e WHERE e.period.startDate = ?1", Long.class);
selectQuery.setParameter(1, employmentPeriod.getStartDate());
long nr = (long) selectQuery.getSingleResult();
assertEquals("updateEmbedded: unexpected number of changed values in the database",
nrOfEmps, nr);
} finally {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
}
}

public void updateEmbeddedObjectWithNull()
{
if ((getPersistenceUnitServerSession()).getPlatform().isSymfoware()) {
getPersistenceUnitServerSession().logMessage("Test updateEmbedded skipped for this platform, "
+ "Symfoware doesn't support UpdateAll/DeleteAll on multi-table objects (see rfe 298193).");
return;
}
EntityManager em = createEntityManager();

int nrOfEmps = executeJPQLReturningInt(
em, "SELECT COUNT(e) FROM Employee e");

// test query
String update = "UPDATE Employee e SET e.period = ?1";
beginTransaction(em);
try {
Query q = em.createQuery(update);
q.setParameter(1, null);
int updated = q.executeUpdate();
assertEquals("updateEmbedded: wrong number of updated instances",
nrOfEmps, updated);
commitTransaction(em);

// check database changes
int nr = executeJPQLReturningInt(
em, "SELECT COUNT(e) FROM Employee e WHERE e.period.startDate IS NULL");
assertEquals("updateEmbedded: unexpected number of changed values in the database",
nrOfEmps, nr);
} finally {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
}
}

public void updateEmbeddedFieldTest()
{
if ((getPersistenceUnitServerSession()).getPlatform().isSymfoware()) {
Expand Down

0 comments on commit f2eb9b5

Please sign in to comment.