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 <m...@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>