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] Update JPQL queries for Embeddables don't include all fields - bugfix and unit test #2345

Merged
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) 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
Loading