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>