diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 70d85f9d0a..d86d31d5ba 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -93,4 +93,5 @@ CAY-2810 Can't use custom operator expression with aggregate functions CAY-2811 Incorrect SQL building using ColumnQuery with ASTScalar CAY-2813 Regression: Constants.CI_PROPERTY flag is no longer working for MySQL CAY-2815 Incorrect translation of aliased expression -CAY-2827 Saved data-source XML data doesn't correspond to the XSD schema \ No newline at end of file +CAY-2827 Saved data-source XML data doesn't correspond to the XSD schema +CAY-2838 Vertical Inheritance: Problem setting db attribute to null via flattened path \ No newline at end of file diff --git a/cayenne/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java b/cayenne/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java index 91f86bd5d6..3d3b730158 100644 --- a/cayenne/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java +++ b/cayenne/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java @@ -151,7 +151,7 @@ ObjectId processFlattenedPath(ObjectId id, ObjectId finalTargetId, DbEntity enti // should update existing DB row factory.getOrCreate(target, targetId, add ? DbRowOpType.UPDATE : defaultType); } - processRelationship(relationship, srcId, targetId, add); + processRelationship(relationship, srcId, targetId, true); srcId = targetId; // use target as next source.. } } diff --git a/cayenne/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java b/cayenne/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java index 3e9309a02f..67edd45f9c 100644 --- a/cayenne/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java +++ b/cayenne/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java @@ -617,6 +617,115 @@ public void testUpdateWithRelationship() { 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()); + } + + @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()); + } + + @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);