This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/STABLE-4.2 by this push:
new 2361f20a7 CAY-2838 Vertical Inheritance: Problem setting db attribute
to null via flattened path
2361f20a7 is described below
commit 2361f20a74bc6178f9dab40f0920e2a4f2aa6f00
Author: Nikita Timofeev <[email protected]>
AuthorDate: Tue Feb 27 12:42:59 2024 +0400
CAY-2838 Vertical Inheritance: Problem setting db attribute to null via
flattened path
(cherry picked from commit 2bbe6cedd189c56f6e93c41eb8158c2eb840539f)
---
RELEASE-NOTES.txt | 1 +
.../access/flush/ArcValuesCreationHandler.java | 5 +-
.../cayenne/access/VerticalInheritanceIT.java | 124 +++++++++++++++++++++
3 files changed, 128 insertions(+), 2 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index cf9643a37..6044843b1 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -20,6 +20,7 @@ CAY-2809 Cayenne Expression grammar doesn't allow custom
function as an argument
CAY-2810 Can't use custom operator expression with aggregate functions
CAY-2813 Regression: Constants.CI_PROPERTY flag is no longer working for MySQL
CAY-2815 Incorrect translation of aliased expression
+CAY-2838 Vertical Inheritance: Problem setting db attribute to null via
flattened path
CAY-2840 Vertical Inheritance: Missing subclass attributes with joint prefetch
----------------------------------
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
index 91f86bd5d..1ca012aa6 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
+++
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
@@ -151,8 +151,9 @@ class ArcValuesCreationHandler implements
GraphChangeHandler {
// should update existing DB row
factory.getOrCreate(target, targetId, add ?
DbRowOpType.UPDATE : defaultType);
}
- processRelationship(relationship, srcId, targetId, add);
- srcId = targetId; // use target as next source..
+ // should always add data from the intermediate relationship
+ processRelationship(relationship, srcId, targetId,
dbPathIterator.hasNext() || add);
+ srcId = targetId; // use target as next source
}
}
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index 320f22051..e826fa112 100644
---
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -619,6 +619,130 @@ public class VerticalInheritanceIT extends ServerCase {
context.commitChanges();
}
+ /**
+ * @link https://issues.apache.org/jira/browse/CAY-2838
+ */
+ @Test
+ public void testNullifyFlattenedAttribute() {
+ IvConcrete concrete = context.newObject(IvConcrete.class);
+ concrete.setName("Concrete");
+ context.commitChanges();
+
+ concrete.setName(null);
+ context.commitChanges();
+
+ assertNull(concrete.getName());
+
+ long id = Cayenne.longPKForObject(concrete);
+ {
+ ObjectContext cleanContext = runtime.newContext();
+ IvConcrete concreteFetched =
SelectById.query(IvConcrete.class, id).selectOne(cleanContext);
+ assertNull(concreteFetched.getName());
+ }
+ }
+
+ @Test
+ public void testNullifyFlattenedRelationship() {
+ IvOther other = context.newObject(IvOther.class);
+ other.setName("other");
+
+ IvImpl impl = context.newObject(IvImpl.class);
+ impl.setName("Impl 1");
+ impl.setOther1(other);
+ context.commitChanges();
+
+ impl.setOther1(null);
+ context.commitChanges();
+
+ assertNull(impl.getOther1());
+
+ long id = Cayenne.longPKForObject(impl);
+ {
+ ObjectContext cleanContext = runtime.newContext();
+ IvImpl implFetched = SelectById.query(IvImpl.class,
id).selectOne(cleanContext);
+ assertEquals("Impl 1", implFetched.getName());
+ assertNull(implFetched.getOther1());
+ }
+ }
+
+ @Test
+ public void testDeleteFlattenedNoValues() throws SQLException {
+ TableHelper ivAbstractTable = new TableHelper(dbHelper,
"IV_ABSTRACT");
+ ivAbstractTable.setColumns("ID", "PARENT_ID", "TYPE")
+ .setColumnTypes(Types.INTEGER, Types.INTEGER,
Types.CHAR);
+
+ TableHelper ivConcreteTable = new TableHelper(dbHelper,
"IV_CONCRETE");
+ ivConcreteTable.setColumns("ID", "NAME")
+ .setColumnTypes(Types.INTEGER, Types.VARCHAR);
+
+ ivAbstractTable.insert(1, null, "S");
+
+ IvConcrete concrete = SelectById.query(IvConcrete.class,
1).selectOne(context);
+ assertNotNull(concrete);
+ assertNull(concrete.getName());
+
+ context.deleteObject(concrete);
+ context.commitChanges();
+
+ assertEquals(0, ivAbstractTable.getRowCount());
+ assertEquals(0, ivConcreteTable.getRowCount());
+ }
+
+ @Test
+ public void testDeleteFlattenedNullValues() throws SQLException {
+ TableHelper ivAbstractTable = new TableHelper(dbHelper,
"IV_ABSTRACT");
+ ivAbstractTable.setColumns("ID", "PARENT_ID", "TYPE")
+ .setColumnTypes(Types.INTEGER, Types.INTEGER,
Types.CHAR);
+
+ TableHelper ivConcreteTable = new TableHelper(dbHelper,
"IV_CONCRETE");
+ ivConcreteTable.setColumns("ID", "NAME")
+ .setColumnTypes(Types.INTEGER, Types.VARCHAR);
+
+ ivAbstractTable.insert(1, null, "S");
+ ivConcreteTable.insert(1, null);
+
+ IvConcrete concrete = SelectById.query(IvConcrete.class,
1).selectOne(context);
+ assertNotNull(concrete);
+ assertNull(concrete.getName());
+
+ context.deleteObject(concrete);
+ context.commitChanges();
+
+ assertEquals(0, ivAbstractTable.getRowCount());
+ assertEquals(0, ivConcreteTable.getRowCount());
+ }
+
+ @Test
+ public void testDeleteFlattenedNullifyValues() throws SQLException {
+ TableHelper ivAbstractTable = new TableHelper(dbHelper,
"IV_ABSTRACT");
+ ivAbstractTable.setColumns("ID", "PARENT_ID", "TYPE")
+ .setColumnTypes(Types.INTEGER, Types.INTEGER,
Types.CHAR);
+
+ TableHelper ivConcreteTable = new TableHelper(dbHelper,
"IV_CONCRETE");
+ ivConcreteTable.setColumns("ID", "NAME")
+ .setColumnTypes(Types.INTEGER, Types.VARCHAR);
+
+ ivAbstractTable.insert(1, null, "S");
+ ivConcreteTable.insert(1, "test");
+
+ IvConcrete concrete = SelectById.query(IvConcrete.class,
1).selectOne(context);
+ assertNotNull(concrete);
+ assertEquals("test", concrete.getName());
+
+ concrete.setName(null);
+ context.commitChanges();
+ assertNull(concrete.getName());
+
+ assertEquals(1, ivAbstractTable.getRowCount());
+ assertEquals(1, ivConcreteTable.getRowCount());
+
+ context.deleteObject(concrete);
+ context.commitChanges();
+
+ assertEquals(0, ivAbstractTable.getRowCount());
+ assertEquals(0, ivConcreteTable.getRowCount());
+ }
+
@Test//(expected = ValidationException.class) // other2 is not
mandatory for now
public void testInsertWithAttributeAndRelationship() {
IvOther other = context.newObject(IvOther.class);