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 <stari...@gmail.com>
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);

Reply via email to