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

commit ca6f9d944d2995e4ab76728695c0cd9097170c4a
Author: Jadon Hansell <130694311+jghans...@users.noreply.github.com>
AuthorDate: Thu Feb 29 13:08:11 2024 +0400

    CAY-2838 Vertical Inheritance: Problem setting db attribute to null via 
flattened path
---
 .../cayenne/access/VerticalInheritanceIT.java      | 29 ++++++++++++++++++++++
 .../inheritance_vertical/auto/_IvAbstract.java     | 19 ++++++++++++++
 .../inheritance_vertical/auto/_IvConcrete.java     | 17 +++++++++++++
 .../test/resources/inheritance-vertical.map.xml    |  9 +++++++
 4 files changed, 74 insertions(+)

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 e826fa112..4f9a33196 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
@@ -743,6 +743,35 @@ public class VerticalInheritanceIT extends ServerCase {
                assertEquals(0, ivConcreteTable.getRowCount());
        }
 
+       @Test
+       public void testNullifyFlattenedRelationshipConcreteToAbstract() 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", "RELATED_ABSTRACT_ID")
+                               .setColumnTypes(Types.INTEGER, Types.VARCHAR, 
Types.INTEGER);
+
+               ivAbstractTable.insert(1, null, "S");
+               ivConcreteTable.insert(1, "One", null);
+               ivAbstractTable.insert(2, null, "S");
+               ivConcreteTable.insert(2, "Two", 1);
+
+               IvConcrete concrete = SelectById.query(IvConcrete.class, 
2).selectOne(context);
+               concrete.setRelatedAbstract(null);
+
+               context.commitChanges();
+               assertNull(concrete.getRelatedAbstract());
+
+               {
+                       ObjectContext cleanContext = runtime.newContext();
+                       IvConcrete concreteFetched = 
SelectById.query(IvConcrete.class, 2).selectOne(cleanContext);
+                       assertEquals("Two", concreteFetched.getName());
+                       assertNull(concreteFetched.getRelatedAbstract());
+               }
+       }
+
        @Test//(expected = ValidationException.class) // other2 is not 
mandatory for now
        public void testInsertWithAttributeAndRelationship() {
                IvOther other = context.newObject(IvOther.class);
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
index 48d19280c..e8669b2e4 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
@@ -5,8 +5,10 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.EntityProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.inheritance_vertical.IvConcrete;
 
 /**
  * Class _IvAbstract was generated by Cayenne.
@@ -21,9 +23,11 @@ public abstract class _IvAbstract extends BaseDataObject {
     public static final String ID_PK_COLUMN = "ID";
 
     public static final StringProperty<String> TYPE = 
PropertyFactory.createString("type", String.class);
+    public static final EntityProperty<IvConcrete> RELATED_CONCRETE = 
PropertyFactory.createEntity("relatedConcrete", IvConcrete.class);
 
     protected String type;
 
+    protected Object relatedConcrete;
 
     public void setType(String type) {
         beforePropertyWrite("type", this.type, type);
@@ -35,6 +39,14 @@ public abstract class _IvAbstract extends BaseDataObject {
         return this.type;
     }
 
+    public void setRelatedConcrete(IvConcrete relatedConcrete) {
+        setToOneTarget("relatedConcrete", relatedConcrete, true);
+    }
+
+    public IvConcrete getRelatedConcrete() {
+        return (IvConcrete)readProperty("relatedConcrete");
+    }
+
     @Override
     public Object readPropertyDirectly(String propName) {
         if(propName == null) {
@@ -44,6 +56,8 @@ public abstract class _IvAbstract extends BaseDataObject {
         switch(propName) {
             case "type":
                 return this.type;
+            case "relatedConcrete":
+                return this.relatedConcrete;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -59,6 +73,9 @@ public abstract class _IvAbstract extends BaseDataObject {
             case "type":
                 this.type = (String)val;
                 break;
+            case "relatedConcrete":
+                this.relatedConcrete = val;
+                break;
             default:
                 super.writePropertyDirectly(propName, val);
         }
@@ -76,12 +93,14 @@ public abstract class _IvAbstract extends BaseDataObject {
     protected void writeState(ObjectOutputStream out) throws IOException {
         super.writeState(out);
         out.writeObject(this.type);
+        out.writeObject(this.relatedConcrete);
     }
 
     @Override
     protected void readState(ObjectInputStream in) throws IOException, 
ClassNotFoundException {
         super.readState(in);
         this.type = (String)in.readObject();
+        this.relatedConcrete = in.readObject();
     }
 
 }
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvConcrete.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvConcrete.java
index 2f34f3ac0..fd5f2073f 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvConcrete.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvConcrete.java
@@ -27,11 +27,13 @@ public abstract class _IvConcrete extends IvAbstract {
     public static final StringProperty<String> NAME = 
PropertyFactory.createString("name", String.class);
     public static final ListProperty<IvConcrete> CHILDREN = 
PropertyFactory.createList("children", IvConcrete.class);
     public static final EntityProperty<IvConcrete> PARENT = 
PropertyFactory.createEntity("parent", IvConcrete.class);
+    public static final EntityProperty<IvAbstract> RELATED_ABSTRACT = 
PropertyFactory.createEntity("relatedAbstract", IvAbstract.class);
 
     protected String name;
 
     protected Object children;
     protected Object parent;
+    protected Object relatedAbstract;
 
     public void setName(String name) {
         beforePropertyWrite("name", this.name, name);
@@ -64,6 +66,14 @@ public abstract class _IvConcrete extends IvAbstract {
         return (IvConcrete)readProperty("parent");
     }
 
+    public void setRelatedAbstract(IvAbstract relatedAbstract) {
+        setToOneTarget("relatedAbstract", relatedAbstract, true);
+    }
+
+    public IvAbstract getRelatedAbstract() {
+        return (IvAbstract)readProperty("relatedAbstract");
+    }
+
     @Override
     public Object readPropertyDirectly(String propName) {
         if(propName == null) {
@@ -77,6 +87,8 @@ public abstract class _IvConcrete extends IvAbstract {
                 return this.children;
             case "parent":
                 return this.parent;
+            case "relatedAbstract":
+                return this.relatedAbstract;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -98,6 +110,9 @@ public abstract class _IvConcrete extends IvAbstract {
             case "parent":
                 this.parent = val;
                 break;
+            case "relatedAbstract":
+                this.relatedAbstract = val;
+                break;
             default:
                 super.writePropertyDirectly(propName, val);
         }
@@ -117,6 +132,7 @@ public abstract class _IvConcrete extends IvAbstract {
         out.writeObject(this.name);
         out.writeObject(this.children);
         out.writeObject(this.parent);
+        out.writeObject(this.relatedAbstract);
     }
 
     @Override
@@ -125,6 +141,7 @@ public abstract class _IvConcrete extends IvAbstract {
         this.name = (String)in.readObject();
         this.children = in.readObject();
         this.parent = in.readObject();
+        this.relatedAbstract = in.readObject();
     }
 
 }
diff --git a/cayenne-server/src/test/resources/inheritance-vertical.map.xml 
b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
index 4fa04258a..7f07d5188 100644
--- a/cayenne-server/src/test/resources/inheritance-vertical.map.xml
+++ b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
@@ -42,6 +42,7 @@
        <db-entity name="IV_CONCRETE">
                <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
                <db-attribute name="NAME" type="VARCHAR" length="100"/>
+               <db-attribute name="RELATED_ABSTRACT_ID" type="INTEGER"/>
        </db-entity>
        <db-entity name="IV_GEN_KEY_ROOT">
                <db-attribute name="DISCRIMINATOR" type="VARCHAR" length="10"/>
@@ -200,6 +201,9 @@
        <db-relationship name="parent" source="IV_ABSTRACT" 
target="IV_ABSTRACT">
                <db-attribute-pair source="PARENT_ID" target="ID"/>
        </db-relationship>
+       <db-relationship name="relatedConcrete" source="IV_ABSTRACT" 
target="IV_CONCRETE">
+               <db-attribute-pair source="ID" target="RELATED_ABSTRACT_ID"/>
+       </db-relationship>
        <db-relationship name="impl" source="IV_BASE" target="IV_IMPL" 
toDependentPK="true">
                <db-attribute-pair source="ID" target="ID"/>
        </db-relationship>
@@ -212,6 +216,9 @@
        <db-relationship name="abstract" source="IV_CONCRETE" 
target="IV_ABSTRACT">
                <db-attribute-pair source="ID" target="ID"/>
        </db-relationship>
+       <db-relationship name="relatedAbstract" source="IV_CONCRETE" 
target="IV_ABSTRACT">
+               <db-attribute-pair source="RELATED_ABSTRACT_ID" target="ID"/>
+       </db-relationship>
        <db-relationship name="sub1" source="IV_GEN_KEY_ROOT" 
target="IV_GEN_KEY_SUB" toDependentPK="true">
                <db-attribute-pair source="ID" target="ID"/>
        </db-relationship>
@@ -270,8 +277,10 @@
                <db-attribute-pair source="IV_ROOT_ID" target="ID"/>
        </db-relationship>
        <obj-relationship name="x" source="Iv2Sub1" target="Iv2X" 
deleteRule="Nullify" db-relationship-path="sub1.x"/>
+       <obj-relationship name="relatedConcrete" source="IvAbstract" 
target="IvConcrete" deleteRule="Nullify" 
db-relationship-path="relatedConcrete.abstract"/>
        <obj-relationship name="others" source="IvBase" target="IvOther" 
deleteRule="Deny" db-relationship-path="others"/>
        <obj-relationship name="children" source="IvConcrete" 
target="IvConcrete" deleteRule="Deny" db-relationship-path="children"/>
+       <obj-relationship name="relatedAbstract" source="IvConcrete" 
target="IvAbstract" deleteRule="Nullify" 
db-relationship-path="concrete.relatedAbstract"/>
        <obj-relationship name="parent" source="IvConcrete" target="IvConcrete" 
deleteRule="Nullify" db-relationship-path="parent"/>
        <obj-relationship name="other1" source="IvImpl" target="IvOther" 
deleteRule="Nullify" db-relationship-path="impl.other1"/>
        <obj-relationship name="other2" source="IvImpl" target="IvOther" 
deleteRule="Nullify" db-relationship-path="impl.other2"/>

Reply via email to