You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2023/02/09 11:27:55 UTC

[cayenne] 01/05: CAY-2792 Fix Insertion Order For Reflexive DataObjects

This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 403d729a70d5a6cf35fa64a8e506caf223d2f055
Author: Matt Watson <ma...@swarmbox.com>
AuthorDate: Mon Feb 6 20:57:46 2023 +0300

    CAY-2792 Fix Insertion Order For Reflexive DataObjects
---
 .../cayenne/CayenneDataObjectReflexiveIT.java      | 110 +++++++++++++++++++++
 .../org/apache/cayenne/testdo/reflexive/Other.java |  28 ++++++
 .../auto/{_Reflexive.java => _Other.java}          |  48 +++------
 .../cayenne/testdo/reflexive/auto/_Reflexive.java  |  18 ++++
 .../src/test/resources/reflexive.map.xml           |  16 +++
 5 files changed, 187 insertions(+), 33 deletions(-)

diff --git a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectReflexiveIT.java b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectReflexiveIT.java
new file mode 100644
index 000000000..1d35d8346
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectReflexiveIT.java
@@ -0,0 +1,110 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne;
+
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.testdo.reflexive.Other;
+import org.apache.cayenne.testdo.reflexive.Reflexive;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+@UseServerRuntime(CayenneProjects.REFLEXIVE_PROJECT)
+public class CayenneDataObjectReflexiveIT extends ServerCase {
+
+    @Inject
+    private ObjectContext context;
+
+    @Inject
+    private ServerRuntime runtime;
+
+    @Test
+    public void addReflexiveParentAndChild() {
+        // can add Reflexive Parent (that belongsTo Other) and Child, 100 times
+        final int attempts = 100;
+        int errors = 0;
+
+        for (int i = 0; i < attempts; i++) {
+            // when parent is created and associated to "Other"
+
+            final Reflexive parent = context.newObject(Reflexive.class);
+            parent.setName("parentA"+i);
+
+            // and child is created and associated to "Parent"
+            final Reflexive child = context.newObject(Reflexive.class);
+            child.setName("childA"+i);
+            child.setToParent(parent);
+
+            try {
+                context.commitChanges();
+            } catch (final Exception e) {
+                errors++;
+                e.printStackTrace();
+                context.rollbackChanges();
+            }
+        }
+
+        // then no error occurred
+        assertEquals(String.format("Failed on %s of %s attempts.", errors, attempts), 0, errors);
+    }
+
+    @Test
+    public void addReflexiveParentAndChildWithOtherRelationshipOnParent() {
+        // can add Reflexive Parent (that belongsTo Other) and Child,
+        // we will do this 100 times, because it randomly does it correctly/incorrectly
+
+        // given some "other" Object
+        final Other other = context.newObject(Other.class);
+        other.setName("OtherB");
+        context.commitChanges();
+
+        final int attempts = 100;
+        int errors = 0;
+
+        for (int i = 0; i < attempts; i++) {
+            // when parent is created and associated to "Other"
+
+            final Reflexive parent = context.newObject(Reflexive.class);
+            parent.setName("parentB"+i);
+            parent.setToOther(other);
+
+            // and child is created and associated to "Parent"
+            final Reflexive child = context.newObject(Reflexive.class);
+            child.setName("childB"+i);
+            child.setToParent(parent);
+
+            try {
+                context.commitChanges();
+            } catch (final Exception e) {
+                errors++;
+                e.printStackTrace();
+                context.rollbackChanges();
+            }
+        }
+
+        // then no error occurred
+        assertEquals(String.format("Failed on %s of %s attempts.", errors, attempts), 0, errors);
+    }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/Other.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/Other.java
new file mode 100644
index 000000000..675034612
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/Other.java
@@ -0,0 +1,28 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.testdo.reflexive;
+
+import org.apache.cayenne.testdo.reflexive.auto._Other;
+
+public class Other extends _Other {
+
+}
+
+
+
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Reflexive.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Other.java
similarity index 68%
copy from cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Reflexive.java
copy to cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Other.java
index a1f79722a..5b4412601 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Reflexive.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Other.java
@@ -20,7 +20,7 @@ import org.apache.cayenne.testdo.reflexive.Reflexive;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Reflexive extends BaseDataObject {
+public abstract class _Other extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
@@ -28,14 +28,11 @@ public abstract class _Reflexive extends BaseDataObject {
     public static final String ID_PK_COLUMN = "ID";
 
     public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
-    public static final ListProperty<Reflexive> CHILDREN = PropertyFactory.createList("children", Reflexive.class);
-    public static final EntityProperty<Reflexive> TO_PARENT = PropertyFactory.createEntity("toParent", Reflexive.class);
+    public static final ListProperty<Reflexive> REFLEXIVES = PropertyFactory.createList("reflexives", Reflexive.class);
 
     protected String name;
 
-    protected Object children;
-    protected Object toParent;
-
+    protected Object reflexives;
     public void setName(String name) {
         beforePropertyWrite("name", this.name, name);
         this.name = name;
@@ -46,25 +43,17 @@ public abstract class _Reflexive extends BaseDataObject {
         return this.name;
     }
 
-    public void addToChildren(Reflexive obj) {
-        addToManyTarget("children", obj, true);
+    public void addToReflexives(Reflexive obj) {
+        addToManyTarget("reflexives", obj, true);
     }
 
-    public void removeFromChildren(Reflexive obj) {
-        removeToManyTarget("children", obj, true);
+    public void removeFromReflexives(Reflexive obj) {
+        removeToManyTarget("reflexives", obj, true);
     }
 
     @SuppressWarnings("unchecked")
-    public List<Reflexive> getChildren() {
-        return (List<Reflexive>)readProperty("children");
-    }
-
-    public void setToParent(Reflexive toParent) {
-        setToOneTarget("toParent", toParent, true);
-    }
-
-    public Reflexive getToParent() {
-        return (Reflexive)readProperty("toParent");
+    public List<Reflexive> getReflexives() {
+        return (List<Reflexive>)readProperty("reflexives");
     }
 
     @Override
@@ -76,10 +65,8 @@ public abstract class _Reflexive extends BaseDataObject {
         switch(propName) {
             case "name":
                 return this.name;
-            case "children":
-                return this.children;
-            case "toParent":
-                return this.toParent;
+            case "reflexives":
+                return this.reflexives;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -95,11 +82,8 @@ public abstract class _Reflexive extends BaseDataObject {
             case "name":
                 this.name = (String)val;
                 break;
-            case "children":
-                this.children = val;
-                break;
-            case "toParent":
-                this.toParent = val;
+            case "reflexives":
+                this.reflexives = val;
                 break;
             default:
                 super.writePropertyDirectly(propName, val);
@@ -118,16 +102,14 @@ public abstract class _Reflexive extends BaseDataObject {
     protected void writeState(ObjectOutputStream out) throws IOException {
         super.writeState(out);
         out.writeObject(this.name);
-        out.writeObject(this.children);
-        out.writeObject(this.toParent);
+        out.writeObject(this.reflexives);
     }
 
     @Override
     protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
         super.readState(in);
         this.name = (String)in.readObject();
-        this.children = in.readObject();
-        this.toParent = in.readObject();
+        this.reflexives = in.readObject();
     }
 
 }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Reflexive.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Reflexive.java
index a1f79722a..b4264d4de 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Reflexive.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/reflexive/auto/_Reflexive.java
@@ -12,6 +12,7 @@ import org.apache.cayenne.exp.property.ListProperty;
 import org.apache.cayenne.exp.property.NumericProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.reflexive.Other;
 import org.apache.cayenne.testdo.reflexive.Reflexive;
 
 /**
@@ -29,11 +30,13 @@ public abstract class _Reflexive extends BaseDataObject {
 
     public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
     public static final ListProperty<Reflexive> CHILDREN = PropertyFactory.createList("children", Reflexive.class);
+    public static final EntityProperty<Other> TO_OTHER = PropertyFactory.createEntity("toOther", Other.class);
     public static final EntityProperty<Reflexive> TO_PARENT = PropertyFactory.createEntity("toParent", Reflexive.class);
 
     protected String name;
 
     protected Object children;
+    protected Object toOther;
     protected Object toParent;
 
     public void setName(String name) {
@@ -59,6 +62,14 @@ public abstract class _Reflexive extends BaseDataObject {
         return (List<Reflexive>)readProperty("children");
     }
 
+    public void setToOther(Other toOther) {
+        setToOneTarget("toOther", toOther, true);
+    }
+
+    public Other getToOther() {
+        return (Other)readProperty("toOther");
+    }
+
     public void setToParent(Reflexive toParent) {
         setToOneTarget("toParent", toParent, true);
     }
@@ -78,6 +89,8 @@ public abstract class _Reflexive extends BaseDataObject {
                 return this.name;
             case "children":
                 return this.children;
+            case "toOther":
+                return this.toOther;
             case "toParent":
                 return this.toParent;
             default:
@@ -98,6 +111,9 @@ public abstract class _Reflexive extends BaseDataObject {
             case "children":
                 this.children = val;
                 break;
+            case "toOther":
+                this.toOther = val;
+                break;
             case "toParent":
                 this.toParent = val;
                 break;
@@ -119,6 +135,7 @@ public abstract class _Reflexive extends BaseDataObject {
         super.writeState(out);
         out.writeObject(this.name);
         out.writeObject(this.children);
+        out.writeObject(this.toOther);
         out.writeObject(this.toParent);
     }
 
@@ -127,6 +144,7 @@ public abstract class _Reflexive extends BaseDataObject {
         super.readState(in);
         this.name = (String)in.readObject();
         this.children = in.readObject();
+        this.toOther = in.readObject();
         this.toParent = in.readObject();
     }
 
diff --git a/cayenne-server/src/test/resources/reflexive.map.xml b/cayenne-server/src/test/resources/reflexive.map.xml
index 28dc79ee8..731b7e764 100644
--- a/cayenne-server/src/test/resources/reflexive.map.xml
+++ b/cayenne-server/src/test/resources/reflexive.map.xml
@@ -4,20 +4,36 @@
 	 xsi:schemaLocation="http://cayenne.apache.org/schema/11/modelMap https://cayenne.apache.org/schema/11/modelMap.xsd"
 	 project-version="11">
 	<property name="defaultPackage" value="org.apache.cayenne.testdo.reflexive"/>
+	<db-entity name="OTHER">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="NAME" type="VARCHAR" isMandatory="true" length="200"/>
+	</db-entity>
 	<db-entity name="REFLEXIVE">
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 		<db-attribute name="NAME" type="VARCHAR" isMandatory="true" length="200"/>
+		<db-attribute name="OTHER_ID" type="INTEGER"/>
 		<db-attribute name="PARENT_ID" type="INTEGER"/>
 	</db-entity>
+	<obj-entity name="Other" className="org.apache.cayenne.testdo.reflexive.Other" dbEntityName="OTHER">
+		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+	</obj-entity>
 	<obj-entity name="Reflexive" className="org.apache.cayenne.testdo.reflexive.Reflexive" dbEntityName="REFLEXIVE">
 		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
 	</obj-entity>
+	<db-relationship name="reflexives" source="OTHER" target="REFLEXIVE" toMany="true">
+		<db-attribute-pair source="ID" target="OTHER_ID"/>
+	</db-relationship>
 	<db-relationship name="children" source="REFLEXIVE" target="REFLEXIVE" toMany="true">
 		<db-attribute-pair source="ID" target="PARENT_ID"/>
 	</db-relationship>
+	<db-relationship name="toOther" source="REFLEXIVE" target="OTHER">
+		<db-attribute-pair source="OTHER_ID" target="ID"/>
+	</db-relationship>
 	<db-relationship name="toParent" source="REFLEXIVE" target="REFLEXIVE">
 		<db-attribute-pair source="PARENT_ID" target="ID"/>
 	</db-relationship>
+	<obj-relationship name="reflexives" source="Other" target="Reflexive" db-relationship-path="reflexives"/>
 	<obj-relationship name="children" source="Reflexive" target="Reflexive" db-relationship-path="children"/>
+	<obj-relationship name="toOther" source="Reflexive" target="Other" db-relationship-path="toOther"/>
 	<obj-relationship name="toParent" source="Reflexive" target="Reflexive" db-relationship-path="toParent"/>
 </data-map>