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"/>