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 2019/03/07 10:53:56 UTC
[cayenne] 01/04: CAY-2521 Expression without Object ID disjoint
issue
This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch STABLE-4.1
in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit eedc9adef5e6048303131d07c4300bc8999edb26
Author: Arseni Bulatski <an...@gmail.com>
AuthorDate: Fri Feb 8 17:50:31 2019 +0300
CAY-2521 Expression without Object ID disjoint issue
---
RELEASE-NOTES.txt | 1 +
.../translator/select/QueryAssemblerHelper.java | 24 ++--
.../java/org/apache/cayenne/query/CAY_2521IT.java | 141 ++++++++++++++++++++
.../org/apache/cayenne/testdo/cay_2521/Issue.java | 28 ++++
.../apache/cayenne/testdo/cay_2521/Location.java | 28 ++++
.../org/apache/cayenne/testdo/cay_2521/Team.java | 28 ++++
.../cayenne/testdo/cay_2521/auto/_Issue.java | 103 +++++++++++++++
.../cayenne/testdo/cay_2521/auto/_Location.java | 145 +++++++++++++++++++++
.../apache/cayenne/testdo/cay_2521/auto/_Team.java | 131 +++++++++++++++++++
.../cayenne/unit/di/server/CayenneProjects.java | 1 +
.../cayenne/unit/di/server/SchemaBuilder.java | 32 ++---
cayenne-server/src/test/resources/cay-2521.map.xml | 80 ++++++++++++
.../src/test/resources/cayenne-cay-2521.xml | 7 +
13 files changed, 725 insertions(+), 24 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 115feb7..a463065 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -57,6 +57,7 @@ CAY-2501 Modeler: DbImport ui not loading columns for MySQL connector v8.0
CAY-2502 DataMap in DataNode tree view disappears after dbImport
CAY-2504 Broken detection logic of NoopEventBridge in DataRowStoreFactory
CAY-2505 EventBridge providers should be bound without scope
+CAY-2521 Expression without Object ID disjoint issue
----------------------------------
Release: 4.1.M2
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QueryAssemblerHelper.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QueryAssemblerHelper.java
index fcdad65..6f624ba 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QueryAssemblerHelper.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QueryAssemblerHelper.java
@@ -19,6 +19,12 @@
package org.apache.cayenne.access.translator.select;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.Persistent;
@@ -26,15 +32,17 @@ import org.apache.cayenne.dba.QuotingStrategy;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.parser.PatternMatchNode;
import org.apache.cayenne.exp.parser.SimpleNode;
-import org.apache.cayenne.map.*;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbJoin;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.JoinType;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.PathComponent;
import org.apache.cayenne.util.CayenneMapEntry;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
/**
* Translates parts of the query to SQL. Always works in the context of parent
* Translator.
@@ -444,7 +452,7 @@ public abstract class QueryAssemblerHelper {
*/
protected void processRelTermination(DbRelationship rel, JoinType joinType, String joinSplitAlias) {
- if (forceJoinForRelations || rel.isToMany()) {
+ if (forceJoinForRelations || rel.isToMany() || !rel.isToPK()) {
// append joins
queryAssembler.dbRelationshipAdded(rel, joinType, joinSplitAlias);
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/CAY_2521IT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/CAY_2521IT.java
new file mode 100644
index 0000000..9bab5e4
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/CAY_2521IT.java
@@ -0,0 +1,141 @@
+/*****************************************************************
+ * 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
+ *
+ * http://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.query;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.List;
+
+import org.apache.cayenne.Cayenne;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.cay_2521.Issue;
+import org.apache.cayenne.testdo.cay_2521.Location;
+import org.apache.cayenne.testdo.cay_2521.Team;
+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.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@UseServerRuntime(CayenneProjects.CAY_2521)
+public class CAY_2521IT extends ServerCase {
+
+ @Inject
+ private ObjectContext context;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ private TableHelper tTeam;
+ private TableHelper tIssue;
+ private TableHelper tLocation;
+
+ @Before
+ public void before() {
+ this.tTeam = new TableHelper(dbHelper, "TEAM1").setColumns("home_location_id", "id")
+ .setColumnTypes(Types.INTEGER, Types.INTEGER);
+ this.tIssue = new TableHelper(dbHelper, "ISSUE").setColumns("home_team_id", "id", "location_id")
+ .setColumnTypes(Types.INTEGER, Types.INTEGER, Types.INTEGER);
+ this.tLocation = new TableHelper(dbHelper, "LOCATION").setColumns("id", "name", "team_id")
+ .setColumnTypes(Types.INTEGER, Types.VARCHAR, Types.INTEGER);
+ }
+
+ @After
+ public void after() throws SQLException {
+ this.tIssue.deleteAll();
+ this.tTeam.deleteAll();
+ this.tLocation.deleteAll();
+ }
+
+ private void createDataSet() throws SQLException {
+ tLocation.insert(71, "Test", null);
+ tTeam.insert(71, 8);
+ tIssue.insert(8, 100, 71);
+ }
+
+ @Test
+ public void testCay_2521() throws SQLException {
+ createDataSet();
+
+ List<Issue> result = ObjectSelect.query(Issue.class)
+ .where(ExpressionFactory.exp("homeTeam = 8"))
+ .prefetch(Issue.HOME_TEAM.disjoint())
+ .prefetch(Issue.HOME_TEAM.dot(Team.HOME_LOCATION).disjoint())
+ .select(context);
+ assertEquals(1, result.size());
+ assertNotNull(result.get(0).getHomeTeam().getHomeLocation());
+ }
+
+ @Test
+ public void testCay_2521_ObjId() throws SQLException {
+ createDataSet();
+
+ Team team = Cayenne.objectForPK(context, Team.class, 8);
+ List<Issue> result = ObjectSelect.query(Issue.class)
+ .where(ExpressionFactory.exp("homeTeam = $id" , (Object) team.getObjectId()))
+ .prefetch(Issue.HOME_TEAM.disjoint())
+ .prefetch(Issue.HOME_TEAM.dot(Team.HOME_LOCATION).disjoint())
+ .select(context);
+ assertEquals(1, result.size());
+ assertNotNull(result.get(0).getHomeTeam().getHomeLocation());
+ }
+
+ @Test
+ public void testColumnQuery() throws SQLException {
+ createDataSet();
+
+ List<Location> result = ObjectSelect
+ .columnQuery(Issue.class, Issue.HOME_TEAM.dot(Team.HOME_LOCATION))
+ .select(context);
+ assertEquals(1, result.size());
+ assertEquals("Test", result.get(0).getName());
+ }
+
+ @Test
+ public void testWithJoin() throws SQLException {
+ createDataSet();
+
+ List<Location> locations = ObjectSelect.query(Location.class)
+ .prefetch(Location.HOME_TEAM.disjoint())
+ .select(context);
+ assertEquals(1, locations.size());
+ assertEquals("Test", locations.get(0).getName());
+ assertNotNull(locations.get(0).getHomeTeam());
+ }
+
+ @Test
+ public void testWithoutJoin() throws SQLException {
+ createDataSet();
+
+ List<Team> teams = ObjectSelect.query(Team.class)
+ .prefetch(Team.HOME_LOCATION.disjoint())
+ .select(context);
+ assertEquals(1, teams.size());
+ assertNotNull(teams.get(0).getHomeLocation());
+ }
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Issue.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Issue.java
new file mode 100644
index 0000000..e517bbf
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Issue.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
+ *
+ * http://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.cay_2521;
+
+import org.apache.cayenne.testdo.cay_2521.auto._Issue;
+
+public class Issue extends _Issue {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Location.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Location.java
new file mode 100644
index 0000000..38a6165
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Location.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
+ *
+ * http://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.cay_2521;
+
+import org.apache.cayenne.testdo.cay_2521.auto._Location;
+
+public class Location extends _Location {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Team.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Team.java
new file mode 100644
index 0000000..75fe28a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/Team.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
+ *
+ * http://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.cay_2521;
+
+import org.apache.cayenne.testdo.cay_2521.auto._Team;
+
+public class Team extends _Team {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Issue.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Issue.java
new file mode 100644
index 0000000..118fbb0
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Issue.java
@@ -0,0 +1,103 @@
+package org.apache.cayenne.testdo.cay_2521.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.testdo.cay_2521.Location;
+import org.apache.cayenne.testdo.cay_2521.Team;
+
+/**
+ * Class _Issue 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 _Issue extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "id";
+
+ public static final Property<Location> LOCATION = Property.create("location", Location.class);
+ public static final Property<Team> HOME_TEAM = Property.create("homeTeam", Team.class);
+
+
+ protected Object location;
+ protected Object homeTeam;
+
+ public void setLocation(Location location) {
+ setToOneTarget("location", location, true);
+ }
+
+ public Location getLocation() {
+ return (Location)readProperty("location");
+ }
+
+ public void setHomeTeam(Team homeTeam) {
+ setToOneTarget("homeTeam", homeTeam, true);
+ }
+
+ public Team getHomeTeam() {
+ return (Team)readProperty("homeTeam");
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "location":
+ return this.location;
+ case "homeTeam":
+ return this.homeTeam;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "location":
+ this.location = val;
+ break;
+ case "homeTeam":
+ this.homeTeam = 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.location);
+ out.writeObject(this.homeTeam);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ this.location = in.readObject();
+ this.homeTeam = in.readObject();
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Location.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Location.java
new file mode 100644
index 0000000..e9f5043
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Location.java
@@ -0,0 +1,145 @@
+package org.apache.cayenne.testdo.cay_2521.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;
+import org.apache.cayenne.testdo.cay_2521.Issue;
+import org.apache.cayenne.testdo.cay_2521.Team;
+
+/**
+ * Class _Location 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 _Location extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "id";
+
+ public static final Property<String> NAME = Property.create("name", String.class);
+ public static final Property<List<Issue>> ISSUES = Property.create("issues", List.class);
+ public static final Property<Team> TEAM = Property.create("team", Team.class);
+ public static final Property<Team> HOME_TEAM = Property.create("homeTeam", Team.class);
+
+ protected String name;
+
+ protected Object issues;
+ protected Object team;
+ protected Object homeTeam;
+
+ public void setName(String name) {
+ beforePropertyWrite("name", this.name, name);
+ this.name = name;
+ }
+
+ public String getName() {
+ beforePropertyRead("name");
+ return this.name;
+ }
+
+ public void addToIssues(Issue obj) {
+ addToManyTarget("issues", obj, true);
+ }
+
+ public void removeFromIssues(Issue obj) {
+ removeToManyTarget("issues", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<Issue> getIssues() {
+ return (List<Issue>)readProperty("issues");
+ }
+
+ public void setTeam(Team team) {
+ setToOneTarget("team", team, true);
+ }
+
+ public Team getTeam() {
+ return (Team)readProperty("team");
+ }
+
+ public void setHomeTeam(Team homeTeam) {
+ setToOneTarget("homeTeam", homeTeam, true);
+ }
+
+ public Team getHomeTeam() {
+ return (Team)readProperty("homeTeam");
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "name":
+ return this.name;
+ case "issues":
+ return this.issues;
+ case "team":
+ return this.team;
+ case "homeTeam":
+ return this.homeTeam;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "name":
+ this.name = (String)val;
+ break;
+ case "issues":
+ this.issues = val;
+ break;
+ case "team":
+ this.team = val;
+ break;
+ case "homeTeam":
+ this.homeTeam = 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.name);
+ out.writeObject(this.issues);
+ out.writeObject(this.team);
+ out.writeObject(this.homeTeam);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ this.name = (String)in.readObject();
+ this.issues = in.readObject();
+ this.team = in.readObject();
+ this.homeTeam = in.readObject();
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Team.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Team.java
new file mode 100644
index 0000000..bd6523c
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2521/auto/_Team.java
@@ -0,0 +1,131 @@
+package org.apache.cayenne.testdo.cay_2521.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;
+import org.apache.cayenne.testdo.cay_2521.Issue;
+import org.apache.cayenne.testdo.cay_2521.Location;
+
+/**
+ * Class _Team 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 _Team extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "id";
+
+ public static final Property<List<Location>> LOCATIONS = Property.create("locations", List.class);
+ public static final Property<Location> HOME_LOCATION = Property.create("homeLocation", Location.class);
+ public static final Property<List<Issue>> ISSUES = Property.create("issues", List.class);
+
+
+ protected Object locations;
+ protected Object homeLocation;
+ protected Object issues;
+
+ public void addToLocations(Location obj) {
+ addToManyTarget("locations", obj, true);
+ }
+
+ public void removeFromLocations(Location obj) {
+ removeToManyTarget("locations", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<Location> getLocations() {
+ return (List<Location>)readProperty("locations");
+ }
+
+ public void setHomeLocation(Location homeLocation) {
+ setToOneTarget("homeLocation", homeLocation, true);
+ }
+
+ public Location getHomeLocation() {
+ return (Location)readProperty("homeLocation");
+ }
+
+ public void addToIssues(Issue obj) {
+ addToManyTarget("issues", obj, true);
+ }
+
+ public void removeFromIssues(Issue obj) {
+ removeToManyTarget("issues", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<Issue> getIssues() {
+ return (List<Issue>)readProperty("issues");
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "locations":
+ return this.locations;
+ case "homeLocation":
+ return this.homeLocation;
+ case "issues":
+ return this.issues;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "locations":
+ this.locations = val;
+ break;
+ case "homeLocation":
+ this.homeLocation = val;
+ break;
+ case "issues":
+ this.issues = 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.locations);
+ out.writeObject(this.homeLocation);
+ out.writeObject(this.issues);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ this.locations = in.readObject();
+ this.homeLocation = in.readObject();
+ this.issues = in.readObject();
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
index 8d58595..fd12258 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
@@ -83,4 +83,5 @@ public class CayenneProjects {
public static final String HYBRID_DATA_OBJECT_PROJECT = "cayenne-hybrid-data-object.xml";
public static final String JAVA8 = "cayenne-java8.xml";
public static final String INHERITANCE_WITH_ENUM_PROJECT = "cayenne-inheritance-with-enum.xml";
+ public static final String CAY_2521 = "cayenne-cay-2521.xml";
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
index d74cffa..9017e99 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
@@ -19,6 +19,21 @@
package org.apache.cayenne.unit.di.server;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.TreeMap;
+
import org.apache.cayenne.access.DataDomain;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.DbGenerator;
@@ -43,21 +58,6 @@ import org.apache.cayenne.unit.UnitDbAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.net.URL;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Types;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.TreeMap;
-
/**
* Default implementation of the AccessStack that has a single DataNode per DataMap.
*/
@@ -82,7 +82,7 @@ public class SchemaBuilder {
"qualified.map.xml", "quoted-identifiers.map.xml", "inheritance-single-table1.map.xml",
"inheritance-vertical.map.xml", "oneway-rels.map.xml", "unsupported-distinct-types.map.xml",
"array-type.map.xml", "cay-2032.map.xml", "weighted-sort.map.xml", "hybrid-data-object.map.xml",
- "java8.map.xml", "inheritance-with-enum.map.xml" };
+ "java8.map.xml", "cay-2521.map.xml", "inheritance-with-enum.map.xml" };
// hardcoded dependent entities that should be excluded
// if LOBs are not supported
diff --git a/cayenne-server/src/test/resources/cay-2521.map.xml b/cayenne-server/src/test/resources/cay-2521.map.xml
new file mode 100644
index 0000000..5cf7a82
--- /dev/null
+++ b/cayenne-server/src/test/resources/cay-2521.map.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<data-map xmlns="http://cayenne.apache.org/schema/10/modelMap"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap https://cayenne.apache.org/schema/10/modelMap.xsd"
+ project-version="10">
+ <property name="defaultPackage" value="org.apache.cayenne.testdo.cay_2521"/>
+ <db-entity name="ISSUE">
+ <db-attribute name="home_team_id" type="INTEGER" length="10"/>
+ <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isGenerated="true" isMandatory="true" length="10"/>
+ <db-attribute name="location_id" type="INTEGER" length="10"/>
+ </db-entity>
+ <db-entity name="LOCATION">
+ <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isGenerated="true" isMandatory="true" length="10"/>
+ <db-attribute name="name" type="VARCHAR" length="45"/>
+ <db-attribute name="team_id" type="INTEGER" length="10"/>
+ </db-entity>
+ <db-entity name="TEAM1">
+ <db-attribute name="home_location_id" type="INTEGER" length="10"/>
+ <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isMandatory="true" length="10"/>
+ </db-entity>
+ <obj-entity name="Issue" className="org.apache.cayenne.testdo.cay_2521.Issue" dbEntityName="ISSUE"/>
+ <obj-entity name="Location" className="org.apache.cayenne.testdo.cay_2521.Location" dbEntityName="LOCATION">
+ <obj-attribute name="name" type="java.lang.String" db-attribute-path="name"/>
+ </obj-entity>
+ <obj-entity name="Team" className="org.apache.cayenne.testdo.cay_2521.Team" dbEntityName="TEAM1"/>
+ <db-relationship name="HOME_TEAM" source="ISSUE" target="TEAM1">
+ <db-attribute-pair source="home_team_id" target="id"/>
+ </db-relationship>
+ <db-relationship name="LOCATION" source="ISSUE" target="LOCATION">
+ <db-attribute-pair source="location_id" target="id"/>
+ </db-relationship>
+ <db-relationship name="ISSUES" source="LOCATION" target="ISSUE" toMany="true">
+ <db-attribute-pair source="id" target="location_id"/>
+ </db-relationship>
+ <db-relationship name="TEAM" source="LOCATION" target="TEAM1">
+ <db-attribute-pair source="team_id" target="id"/>
+ </db-relationship>
+ <db-relationship name="HOME_TEAM" source="LOCATION" target="TEAM1">
+ <db-attribute-pair source="id" target="home_location_id"/>
+ </db-relationship>
+ <db-relationship name="ISSUES" source="TEAM1" target="ISSUE" toMany="true">
+ <db-attribute-pair source="id" target="home_team_id"/>
+ </db-relationship>
+ <db-relationship name="LOCATIONS" source="TEAM1" target="LOCATION" toMany="true">
+ <db-attribute-pair source="id" target="team_id"/>
+ </db-relationship>
+ <db-relationship name="HOME_LOCATION" source="TEAM1" target="LOCATION">
+ <db-attribute-pair source="home_location_id" target="id"/>
+ </db-relationship>
+ <obj-relationship name="location" source="Issue" target="Location" deleteRule="Cascade" db-relationship-path="LOCATION"/>
+ <obj-relationship name="homeTeam" source="Issue" target="Team" deleteRule="Cascade" db-relationship-path="HOME_TEAM"/>
+ <obj-relationship name="issues" source="Location" target="Issue" deleteRule="Cascade" db-relationship-path="ISSUES"/>
+ <obj-relationship name="team" source="Location" target="Team" deleteRule="Cascade" db-relationship-path="TEAM"/>
+ <obj-relationship name="homeTeam" source="Location" target="Team" deleteRule="Cascade" db-relationship-path="HOME_TEAM"/>
+ <obj-relationship name="locations" source="Team" target="Location" deleteRule="Cascade" db-relationship-path="LOCATIONS"/>
+ <obj-relationship name="homeLocation" source="Team" target="Location" deleteRule="Cascade" db-relationship-path="HOME_LOCATION"/>
+ <obj-relationship name="issues" source="Team" target="Issue" deleteRule="Cascade" db-relationship-path="ISSUES"/>
+ <dbImport xmlns="http://cayenne.apache.org/schema/10/dbimport">
+ <forceDataMapCatalog>false</forceDataMapCatalog>
+ <forceDataMapSchema>false</forceDataMapSchema>
+ <namingStrategy>org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator</namingStrategy>
+ <skipPrimaryKeyLoading>false</skipPrimaryKeyLoading>
+ <skipRelationshipsLoading>false</skipRelationshipsLoading>
+ <useJava7Types>false</useJava7Types>
+ <usePrimitives>true</usePrimitives>
+ </dbImport>
+ <cgen xmlns="http://cayenne.apache.org/schema/10/cgen">
+ <destDir>../java</destDir>
+ <mode>entity</mode>
+ <template>templates/v4_1/subclass.vm</template>
+ <superTemplate>templates/v4_1/superclass.vm</superTemplate>
+ <outputPattern>*.java</outputPattern>
+ <makePairs>true</makePairs>
+ <usePkgPath>true</usePkgPath>
+ <overwrite>false</overwrite>
+ <createPropertyNames>false</createPropertyNames>
+ <createPKProperties>false</createPKProperties>
+ <client>false</client>
+ </cgen>
+</data-map>
diff --git a/cayenne-server/src/test/resources/cayenne-cay-2521.xml b/cayenne-server/src/test/resources/cayenne-cay-2521.xml
new file mode 100644
index 0000000..8db3486
--- /dev/null
+++ b/cayenne-server/src/test/resources/cayenne-cay-2521.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain xmlns="http://cayenne.apache.org/schema/10/domain"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain https://cayenne.apache.org/schema/10/domain.xsd"
+ project-version="10">
+ <map name="cay-2521"/>
+</domain>