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
The following commit(s) were added to refs/heads/master by this push: new bc19298 CAY-2728 Add ExtendedType to generate user-friendly exceptions for internally used values bc19298 is described below commit bc1929807b5db5f08258344db182e897b1c3d5b4 Author: Nikita Timofeev <stari...@gmail.com> AuthorDate: Tue Jan 11 17:58:56 2022 +0300 CAY-2728 Add ExtendedType to generate user-friendly exceptions for internally used values --- RELEASE-NOTES.txt | 2 + .../cayenne/access/flush/IdGenerationMarker.java | 8 +- .../access/flush/ObjectIdValueSupplier.java | 8 +- .../types/InternalUnsupportedTypeFactory.java | 82 +++++++++++++ .../cayenne/configuration/server/ServerModule.java | 5 +- .../org/apache/cayenne/CircularDependencyIT.java | 58 +++++++++ .../apache/cayenne/testdo/relationships/E1.java} | 34 +----- .../apache/cayenne/testdo/relationships/E2.java} | 34 +----- .../cayenne/testdo/relationships/auto/_E1.java | 130 +++++++++++++++++++++ .../cayenne/testdo/relationships/auto/_E2.java | 130 +++++++++++++++++++++ .../cayenne/unit/di/server/ServerCaseModule.java | 4 +- .../src/test/resources/relationships.map.xml | 32 +++++ 12 files changed, 464 insertions(+), 63 deletions(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index c63b79c..2591d7c 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -13,6 +13,8 @@ Date: ---------------------------------- Changes/New Features: +CAY-2728 Add ExtendedType to generate user-friendly exceptions for internally used values + Bug Fixes: CAY-2697 Read-only cgen template creates mutator methods for to-many relationships diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java index 1519556..2a10744 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java @@ -22,13 +22,14 @@ package org.apache.cayenne.access.flush; import java.io.Serializable; import org.apache.cayenne.ObjectId; +import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory; /** * Special value that denotes generated id attribute * * @since 4.2 */ -class IdGenerationMarker implements Serializable { +class IdGenerationMarker implements Serializable, InternalUnsupportedTypeFactory.Marker { private static final long serialVersionUID = -5339942931435878094L; private final int id; @@ -49,4 +50,9 @@ class IdGenerationMarker implements Serializable { public int hashCode() { return id; } + + @Override + public String errorMessage() { + return "PK is not generated. Check your PK generation strategy or presence of the mutually dependent entities."; + } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java index da27b99..eac62ef 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java @@ -23,13 +23,14 @@ import java.util.Objects; import java.util.function.Supplier; import org.apache.cayenne.ObjectId; +import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory; /** * Deferred value extracted from ObjectId * * @since 4.2 */ -class ObjectIdValueSupplier implements Supplier<Object> { +class ObjectIdValueSupplier implements Supplier<Object>, InternalUnsupportedTypeFactory.Marker { private final ObjectId id; private final String attribute; @@ -79,4 +80,9 @@ class ObjectIdValueSupplier implements Supplier<Object> { public String toString() { return "{id=" + id + ", attr=" + attribute + '}'; } + + @Override + public String errorMessage() { + return "Value supplier is not resolved before usage."; + } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/types/InternalUnsupportedTypeFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/types/InternalUnsupportedTypeFactory.java new file mode 100644 index 0000000..461a98a --- /dev/null +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/types/InternalUnsupportedTypeFactory.java @@ -0,0 +1,82 @@ +/***************************************************************** + * 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.access.types; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import org.apache.cayenne.CayenneRuntimeException; + +/** + * Extended type factory that produces types for Cayenne internal value types that could potentially make it to the DB. + * ExtendedTypes that produced by this factory just trying to throw user-friendly exception instead of unknown type one. + * + * @since 4.2 + */ +public class InternalUnsupportedTypeFactory implements ExtendedTypeFactory { + + @Override + public ExtendedType<?> getType(Class<?> objectClass) { + if(Marker.class.isAssignableFrom(objectClass)) { + return new ExtendedType<Marker>() { + @Override + public String getClassName() { + return objectClass.getName(); + } + + @Override + public void setJdbcObject(PreparedStatement statement, Marker value, int pos, int type, int scale) { + throw new CayenneRuntimeException(value.errorMessage()); + } + + @Override + public Marker materializeObject(ResultSet rs, int index, int type) { + // this normally shouldn't happen + throw new CayenneRuntimeException("Trying to materialize internal Cayenne value. Check your mapping or report an issue."); + } + + @Override + public Marker materializeObject(CallableStatement rs, int index, int type) { + // this normally shouldn't happen + throw new CayenneRuntimeException("Trying to materialize internal Cayenne value. Check your mapping or report an issue."); + } + + @Override + public String toString(Marker value) { + return "Internal marker of type " + objectClass.getSimpleName(); + } + }; + } + return null; + } + + /** + * Marker interface, that should be used by any internal value types, that could potentially get to the SQL + */ + public interface Marker { + /** + * Error message in case this object made it to the DB + */ + default String errorMessage() { + return "Trying to use internal type in the query."; + } + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java index 1d12d8f..edd6a15 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java @@ -61,7 +61,7 @@ import org.apache.cayenne.access.types.ExtendedTypeFactory; import org.apache.cayenne.access.types.FloatType; import org.apache.cayenne.access.types.GeoJsonType; import org.apache.cayenne.access.types.IntegerType; -import org.apache.cayenne.access.types.JsonType; +import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory; import org.apache.cayenne.access.types.LocalDateTimeValueType; import org.apache.cayenne.access.types.LocalDateValueType; import org.apache.cayenne.access.types.LocalTimeValueType; @@ -434,7 +434,8 @@ public class ServerModule implements Module { .add(GeoJsonType.class) .add(WktType.class); contributeUserTypes(binder); - contributeTypeFactories(binder); + contributeTypeFactories(binder) + .add(new InternalUnsupportedTypeFactory()); // Custom ValueObjects types contribution contributeValueObjectTypes(binder) diff --git a/cayenne-server/src/test/java/org/apache/cayenne/CircularDependencyIT.java b/cayenne-server/src/test/java/org/apache/cayenne/CircularDependencyIT.java new file mode 100644 index 0000000..6cfc68f --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/CircularDependencyIT.java @@ -0,0 +1,58 @@ +/***************************************************************** + * 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.di.Inject; +import org.apache.cayenne.testdo.relationships.E1; +import org.apache.cayenne.testdo.relationships.E2; +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.*; + +@UseServerRuntime(CayenneProjects.RELATIONSHIPS_PROJECT) +public class CircularDependencyIT extends ServerCase { + + @Inject + private ObjectContext context; + + @Test() + public void testCycle() { + E1 e1 = context.newObject(E1.class); + E2 e2 = context.newObject(E2.class); + + e1.setText("e1 #" + 1); + e2.setText("e2 #" + 2); + + e1.setE2(e2); + e2.setE1(e1); + + try { + context.commitChanges(); + fail("Exception should be thrown here"); + } catch (CayenneRuntimeException ex) { + assertTrue("Unexpected exception message: " + ex.getMessage(), + ex.getMessage().contains("PK is not generated")); + } + + } +} diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E1.java similarity index 53% copy from cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java copy to cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E1.java index 1519556..60069b0 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E1.java @@ -7,7 +7,7 @@ * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -17,36 +17,12 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.flush; +package org.apache.cayenne.testdo.relationships; -import java.io.Serializable; +import org.apache.cayenne.testdo.relationships.auto._E1; -import org.apache.cayenne.ObjectId; +public class E1 extends _E1 { -/** - * Special value that denotes generated id attribute - * - * @since 4.2 - */ -class IdGenerationMarker implements Serializable { - private static final long serialVersionUID = -5339942931435878094L; - - private final int id; - - IdGenerationMarker(ObjectId id) { - this.id = id.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - IdGenerationMarker that = (IdGenerationMarker) o; - return id == that.id; - } + private static final long serialVersionUID = 1L; - @Override - public int hashCode() { - return id; - } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E2.java similarity index 53% copy from cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java copy to cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E2.java index 1519556..bf1065a 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E2.java @@ -7,7 +7,7 @@ * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -17,36 +17,12 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.access.flush; +package org.apache.cayenne.testdo.relationships; -import java.io.Serializable; +import org.apache.cayenne.testdo.relationships.auto._E2; -import org.apache.cayenne.ObjectId; +public class E2 extends _E2 { -/** - * Special value that denotes generated id attribute - * - * @since 4.2 - */ -class IdGenerationMarker implements Serializable { - private static final long serialVersionUID = -5339942931435878094L; - - private final int id; - - IdGenerationMarker(ObjectId id) { - this.id = id.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - IdGenerationMarker that = (IdGenerationMarker) o; - return id == that.id; - } + private static final long serialVersionUID = 1L; - @Override - public int hashCode() { - return id; - } } diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E1.java new file mode 100644 index 0000000..26f81c1 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E1.java @@ -0,0 +1,130 @@ +package org.apache.cayenne.testdo.relationships.auto; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.List; + +import org.apache.cayenne.BaseDataObject; +import org.apache.cayenne.exp.property.EntityProperty; +import org.apache.cayenne.exp.property.ListProperty; +import org.apache.cayenne.exp.property.PropertyFactory; +import org.apache.cayenne.exp.property.StringProperty; +import org.apache.cayenne.testdo.relationships.E2; + +/** + * Class _E1 was generated by Cayenne. + * It is probably a good idea to avoid changing this class manually, + * since it may be overwritten next time code is regenerated. + * If you need to make any customizations, please use subclass. + */ +public abstract class _E1 extends BaseDataObject { + + private static final long serialVersionUID = 1L; + + public static final String ID_PK_COLUMN = "id"; + + public static final StringProperty<String> TEXT = PropertyFactory.createString("text", String.class); + public static final EntityProperty<E2> E2 = PropertyFactory.createEntity("e2", E2.class); + public static final ListProperty<E2> E2S = PropertyFactory.createList("e2s", E2.class); + + protected String text; + + protected Object e2; + protected Object e2s; + + public void setText(String text) { + beforePropertyWrite("text", this.text, text); + this.text = text; + } + + public String getText() { + beforePropertyRead("text"); + return this.text; + } + + public void setE2(E2 e2) { + setToOneTarget("e2", e2, true); + } + + public E2 getE2() { + return (E2)readProperty("e2"); + } + + public void addToE2s(E2 obj) { + addToManyTarget("e2s", obj, true); + } + + public void removeFromE2s(E2 obj) { + removeToManyTarget("e2s", obj, true); + } + + @SuppressWarnings("unchecked") + public List<E2> getE2s() { + return (List<E2>)readProperty("e2s"); + } + + @Override + public Object readPropertyDirectly(String propName) { + if(propName == null) { + throw new IllegalArgumentException(); + } + + switch(propName) { + case "text": + return this.text; + case "e2": + return this.e2; + case "e2s": + return this.e2s; + default: + return super.readPropertyDirectly(propName); + } + } + + @Override + public void writePropertyDirectly(String propName, Object val) { + if(propName == null) { + throw new IllegalArgumentException(); + } + + switch (propName) { + case "text": + this.text = (String)val; + break; + case "e2": + this.e2 = val; + break; + case "e2s": + this.e2s = val; + break; + default: + super.writePropertyDirectly(propName, val); + } + } + + private void writeObject(ObjectOutputStream out) throws IOException { + writeSerialized(out); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + readSerialized(in); + } + + @Override + protected void writeState(ObjectOutputStream out) throws IOException { + super.writeState(out); + out.writeObject(this.text); + out.writeObject(this.e2); + out.writeObject(this.e2s); + } + + @Override + protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException { + super.readState(in); + this.text = (String)in.readObject(); + this.e2 = in.readObject(); + this.e2s = in.readObject(); + } + +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E2.java new file mode 100644 index 0000000..1a5e35d --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E2.java @@ -0,0 +1,130 @@ +package org.apache.cayenne.testdo.relationships.auto; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.List; + +import org.apache.cayenne.BaseDataObject; +import org.apache.cayenne.exp.property.EntityProperty; +import org.apache.cayenne.exp.property.ListProperty; +import org.apache.cayenne.exp.property.PropertyFactory; +import org.apache.cayenne.exp.property.StringProperty; +import org.apache.cayenne.testdo.relationships.E1; + +/** + * Class _E2 was generated by Cayenne. + * It is probably a good idea to avoid changing this class manually, + * since it may be overwritten next time code is regenerated. + * If you need to make any customizations, please use subclass. + */ +public abstract class _E2 extends BaseDataObject { + + private static final long serialVersionUID = 1L; + + public static final String ID_PK_COLUMN = "id"; + + public static final StringProperty<String> TEXT = PropertyFactory.createString("text", String.class); + public static final EntityProperty<E1> E1 = PropertyFactory.createEntity("e1", E1.class); + public static final ListProperty<E1> E1S = PropertyFactory.createList("e1s", E1.class); + + protected String text; + + protected Object e1; + protected Object e1s; + + public void setText(String text) { + beforePropertyWrite("text", this.text, text); + this.text = text; + } + + public String getText() { + beforePropertyRead("text"); + return this.text; + } + + public void setE1(E1 e1) { + setToOneTarget("e1", e1, true); + } + + public E1 getE1() { + return (E1)readProperty("e1"); + } + + public void addToE1s(E1 obj) { + addToManyTarget("e1s", obj, true); + } + + public void removeFromE1s(E1 obj) { + removeToManyTarget("e1s", obj, true); + } + + @SuppressWarnings("unchecked") + public List<E1> getE1s() { + return (List<E1>)readProperty("e1s"); + } + + @Override + public Object readPropertyDirectly(String propName) { + if(propName == null) { + throw new IllegalArgumentException(); + } + + switch(propName) { + case "text": + return this.text; + case "e1": + return this.e1; + case "e1s": + return this.e1s; + default: + return super.readPropertyDirectly(propName); + } + } + + @Override + public void writePropertyDirectly(String propName, Object val) { + if(propName == null) { + throw new IllegalArgumentException(); + } + + switch (propName) { + case "text": + this.text = (String)val; + break; + case "e1": + this.e1 = val; + break; + case "e1s": + this.e1s = val; + break; + default: + super.writePropertyDirectly(propName, val); + } + } + + private void writeObject(ObjectOutputStream out) throws IOException { + writeSerialized(out); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + readSerialized(in); + } + + @Override + protected void writeState(ObjectOutputStream out) throws IOException { + super.writeState(out); + out.writeObject(this.text); + out.writeObject(this.e1); + out.writeObject(this.e1s); + } + + @Override + protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException { + super.readState(in); + this.text = (String)in.readObject(); + this.e1 = in.readObject(); + this.e1s = in.readObject(); + } + +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java index 27a8e5a..08e3801 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java @@ -42,6 +42,7 @@ import org.apache.cayenne.access.types.DoubleType; import org.apache.cayenne.access.types.DurationType; import org.apache.cayenne.access.types.FloatType; import org.apache.cayenne.access.types.IntegerType; +import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory; import org.apache.cayenne.access.types.LocalDateTimeValueType; import org.apache.cayenne.access.types.LocalDateValueType; import org.apache.cayenne.access.types.LocalTimeValueType; @@ -223,7 +224,8 @@ public class ServerCaseModule implements Module { .add(new CalendarType<>(Calendar.class)) .add(new DurationType()); ServerModule.contributeUserTypes(binder); - ServerModule.contributeTypeFactories(binder); + ServerModule.contributeTypeFactories(binder) + .add(new InternalUnsupportedTypeFactory()); ServerModule.contributeValueObjectTypes(binder) .add(BigIntegerValueType.class) .add(BigDecimalValueType.class) diff --git a/cayenne-server/src/test/resources/relationships.map.xml b/cayenne-server/src/test/resources/relationships.map.xml index b487db9..7f4b4f5 100644 --- a/cayenne-server/src/test/resources/relationships.map.xml +++ b/cayenne-server/src/test/resources/relationships.map.xml @@ -22,6 +22,22 @@ <db-attribute name="NAME" type="VARCHAR" length="100"/> <db-attribute name="RELATIONSHIP_HELPER_ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/> </db-entity> + <db-entity name="CYCLE_E1"> + <db-attribute name="e2_id" type="INTEGER"/> + <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isGenerated="true" isMandatory="true"/> + <db-attribute name="text" type="VARCHAR" length="128"/> + </db-entity> + <db-entity name="CYCLE_E2"> + <db-attribute name="e1_id" type="INTEGER"/> + <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isGenerated="true" isMandatory="true"/> + <db-attribute name="text" type="VARCHAR" length="128"/> + </db-entity> + <obj-entity name="CYCLE_E1" className="org.apache.cayenne.testdo.relationships.E1" dbEntityName="CYCLE_E1"> + <obj-attribute name="text" type="java.lang.String" db-attribute-path="text"/> + </obj-entity> + <obj-entity name="CYCLE_E2" className="org.apache.cayenne.testdo.relationships.E2" dbEntityName="CYCLE_E2"> + <obj-attribute name="text" type="java.lang.String" db-attribute-path="text"/> + </obj-entity> <obj-entity name="FkOfDifferentType" className="org.apache.cayenne.testdo.relationships.FkOfDifferentType" dbEntityName="FK_OF_DIFFERENT_TYPE"/> <obj-entity name="MeaningfulFK" className="org.apache.cayenne.testdo.relationships.MeaningfulFK" dbEntityName="MEANINGFUL_FK"> <obj-attribute name="relationshipHelperID" type="int" db-attribute-path="RELATIONSHIP_HELPER_ID"/> @@ -56,6 +72,22 @@ <db-relationship name="reflexiveAndToOneArray" source="RELATIONSHIP_HELPER" target="REFLEXIVE_AND_TO_ONE" toMany="true"> <db-attribute-pair source="RELATIONSHIP_HELPER_ID" target="RELATIONSHIP_HELPER_ID"/> </db-relationship> + <db-relationship name="e2" source="CYCLE_E1" target="CYCLE_E2"> + <db-attribute-pair source="e2_id" target="id"/> + </db-relationship> + <db-relationship name="e2s" source="CYCLE_E1" target="CYCLE_E2" toMany="true"> + <db-attribute-pair source="id" target="e1_id"/> + </db-relationship> + <db-relationship name="e1" source="CYCLE_E2" target="CYCLE_E1"> + <db-attribute-pair source="e1_id" target="id"/> + </db-relationship> + <db-relationship name="e1s" source="CYCLE_E2" target="CYCLE_E1" toMany="true"> + <db-attribute-pair source="id" target="e2_id"/> + </db-relationship> + <obj-relationship name="e2" source="CYCLE_E1" target="CYCLE_E2" deleteRule="Nullify" db-relationship-path="e2"/> + <obj-relationship name="e2s" source="CYCLE_E1" target="CYCLE_E2" deleteRule="Deny" db-relationship-path="e2s"/> + <obj-relationship name="e1" source="CYCLE_E2" target="CYCLE_E1" deleteRule="Nullify" db-relationship-path="e1"/> + <obj-relationship name="e1s" source="CYCLE_E2" target="CYCLE_E1" deleteRule="Deny" db-relationship-path="e1s"/> <obj-relationship name="relationshipHelper" source="FkOfDifferentType" target="RelationshipHelper" db-relationship-path="relationshipHelper"/> <obj-relationship name="toRelationshipHelper" source="MeaningfulFK" target="RelationshipHelper" db-relationship-path="toRelationshipHelper"/> <obj-relationship name="children" source="ReflexiveAndToOne" target="ReflexiveAndToOne" db-relationship-path="children"/>