This is an automated email from the ASF dual-hosted git repository. abulatski pushed a commit to branch STABLE-4.1 in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit 5999f6af8e0e3acf36293f4ace2adf7efe85da2f Author: Nikita Timofeev <stari...@gmail.com> AuthorDate: Tue May 21 17:24:07 2019 +0300 CAY-2582 Double insert of manyToMany relationship mapped to Set test case from PR #385 (cherry picked from commit 326f1de071cc871561891557baf5879bd1ba06ce) --- .../java/org/apache/cayenne/ManyToManyJoinIT.java | 51 ++++++++++ .../relationships_many_to_many_join/Author.java | 9 ++ .../relationships_many_to_many_join/Song.java | 9 ++ .../auto/_Author.java | 86 ++++++++++++++++ .../auto/_Song.java | 110 +++++++++++++++++++++ .../cayenne/unit/di/server/CayenneProjects.java | 1 + .../cayenne/unit/di/server/SchemaBuilder.java | 2 +- .../cayenne-relationships-many-to-many-join.xml | 7 ++ .../relationships-many-to-many-join.map.xml | 38 +++++++ 9 files changed, 312 insertions(+), 1 deletion(-) diff --git a/cayenne-server/src/test/java/org/apache/cayenne/ManyToManyJoinIT.java b/cayenne-server/src/test/java/org/apache/cayenne/ManyToManyJoinIT.java new file mode 100644 index 0000000..0949b5e --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/ManyToManyJoinIT.java @@ -0,0 +1,51 @@ +/***************************************************************** + * 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 static org.junit.Assert.*; + +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.testdo.relationships_many_to_many_join.Author; +import org.apache.cayenne.testdo.relationships_many_to_many_join.Song; +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; + +@UseServerRuntime(CayenneProjects.RELATIONSHIPS_MANY_TO_MANY_JOIN_PROJECT) +public class ManyToManyJoinIT extends ServerCase { + + @Inject + private ObjectContext context; + + @Test + public void testManyToManyJoinWithFlattenedRelationship() throws Exception { + Author author = context.newObject(Author.class); + author.setName("Bob Dylan"); + + Song song = context.newObject(Song.class); + song.setName("House of the Rising Sun"); + + song.addToAuthors(author); + + context.commitChanges(); + assertEquals(author, song.getAuthors().iterator().next()); + } + +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/Author.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/Author.java new file mode 100644 index 0000000..a50741e --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/Author.java @@ -0,0 +1,9 @@ +package org.apache.cayenne.testdo.relationships_many_to_many_join; + +import org.apache.cayenne.testdo.relationships_many_to_many_join.auto._Author; + +public class Author extends _Author { + + private static final long serialVersionUID = 1L; + +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/Song.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/Song.java new file mode 100644 index 0000000..8df7056 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/Song.java @@ -0,0 +1,9 @@ +package org.apache.cayenne.testdo.relationships_many_to_many_join; + +import org.apache.cayenne.testdo.relationships_many_to_many_join.auto._Song; + +public class Song extends _Song { + + private static final long serialVersionUID = 1L; + +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/auto/_Author.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/auto/_Author.java new file mode 100644 index 0000000..11554d9 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/auto/_Author.java @@ -0,0 +1,86 @@ +package org.apache.cayenne.testdo.relationships_many_to_many_join.auto; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.apache.cayenne.BaseDataObject; +import org.apache.cayenne.exp.Property; + +/** + * Class _Author 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 _Author extends BaseDataObject { + + private static final long serialVersionUID = 1L; + + public static final String AUTHOR_ID_PK_COLUMN = "AUTHOR_ID"; + + public static final Property<String> NAME = Property.create("name", String.class); + + protected String name; + + + public void setName(String name) { + beforePropertyWrite("name", this.name, name); + this.name = name; + } + + public String getName() { + beforePropertyRead("name"); + return this.name; + } + + @Override + public Object readPropertyDirectly(String propName) { + if(propName == null) { + throw new IllegalArgumentException(); + } + + switch(propName) { + case "name": + return this.name; + 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; + 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); + } + + @Override + protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException { + super.readState(in); + this.name = (String)in.readObject(); + } + +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/auto/_Song.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/auto/_Song.java new file mode 100644 index 0000000..15160ca --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships_many_to_many_join/auto/_Song.java @@ -0,0 +1,110 @@ +package org.apache.cayenne.testdo.relationships_many_to_many_join.auto; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Set; + +import org.apache.cayenne.BaseDataObject; +import org.apache.cayenne.exp.Property; +import org.apache.cayenne.testdo.relationships_many_to_many_join.Author; + +/** + * Class _Song 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 _Song extends BaseDataObject { + + private static final long serialVersionUID = 1L; + + public static final String SONG_ID_PK_COLUMN = "SONG_ID"; + + public static final Property<String> NAME = Property.create("name", String.class); + public static final Property<Set<Author>> AUTHORS = Property.create("authors", Set.class); + + protected String name; + + protected Object authors; + + public void setName(String name) { + beforePropertyWrite("name", this.name, name); + this.name = name; + } + + public String getName() { + beforePropertyRead("name"); + return this.name; + } + + public void addToAuthors(Author obj) { + addToManyTarget("authors", obj, true); + } + + public void removeFromAuthors(Author obj) { + removeToManyTarget("authors", obj, true); + } + + @SuppressWarnings("unchecked") + public Set<Author> getAuthors() { + return (Set<Author>)readProperty("authors"); + } + + @Override + public Object readPropertyDirectly(String propName) { + if(propName == null) { + throw new IllegalArgumentException(); + } + + switch(propName) { + case "name": + return this.name; + case "authors": + return this.authors; + 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 "authors": + this.authors = 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.authors); + } + + @Override + protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException { + super.readState(in); + this.name = (String)in.readObject(); + this.authors = 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 fd12258..e1e79a6 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 @@ -61,6 +61,7 @@ public class CayenneProjects { public static final String REFLEXIVE_PROJECT = "cayenne-reflexive.xml"; public static final String RELATIONSHIPS_PROJECT = "cayenne-relationships.xml"; public static final String RELATIONSHIPS_ACTIVITY_PROJECT = "cayenne-relationships-activity.xml"; + public static final String RELATIONSHIPS_MANY_TO_MANY_JOIN_PROJECT = "cayenne-relationships-many-to-many-join.xml"; public static final String RELATIONSHIPS_CHILD_MASTER_PROJECT = "cayenne-relationships-child-master.xml"; public static final String RELATIONSHIPS_CLOB_PROJECT = "cayenne-relationships-clob.xml"; public static final String RELATIONSHIPS_COLLECTION_TO_MANY_PROJECT = "cayenne-relationships-collection-to-many.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 9017e99..ad6647c 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 @@ -74,7 +74,7 @@ public class SchemaBuilder { "locking.map.xml", "soft-delete.map.xml", "empty.map.xml", "relationships.map.xml", "relationships-activity.map.xml", "relationships-delete-rules.map.xml", "relationships-collection-to-many.map.xml", "relationships-child-master.map.xml", - "relationships-clob.map.xml", "relationships-flattened.map.xml", "relationships-set-to-many.map.xml", + "relationships-clob.map.xml", "relationships-flattened.map.xml", "relationships-many-to-many-join.map.xml", "relationships-set-to-many.map.xml", "relationships-to-many-fk.map.xml", "relationships-to-one-fk.map.xml", "return-types.map.xml", "uuid.map.xml", "multi-tier.map.xml", "reflexive.map.xml", "delete-rules.map.xml", "lifecycle-callbacks-order.map.xml", "lifecycles.map.xml", "map-to-many.map.xml", "toone.map.xml", "meaningful-pk.map.xml", diff --git a/cayenne-server/src/test/resources/cayenne-relationships-many-to-many-join.xml b/cayenne-server/src/test/resources/cayenne-relationships-many-to-many-join.xml new file mode 100644 index 0000000..0121356 --- /dev/null +++ b/cayenne-server/src/test/resources/cayenne-relationships-many-to-many-join.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="relationships-many-to-many-join"/> +</domain> diff --git a/cayenne-server/src/test/resources/relationships-many-to-many-join.map.xml b/cayenne-server/src/test/resources/relationships-many-to-many-join.map.xml new file mode 100644 index 0000000..38ef803 --- /dev/null +++ b/cayenne-server/src/test/resources/relationships-many-to-many-join.map.xml @@ -0,0 +1,38 @@ +<?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.relationships_many_to_many_join"/> + <db-entity name="X_AUTHOR"> + <db-attribute name="AUTHOR_ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/> + <db-attribute name="AUTHOR_NAME" type="VARCHAR" isMandatory="true" length="50"/> + </db-entity> + <db-entity name="X_SONG"> + <db-attribute name="SONG_ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/> + <db-attribute name="SONG_NAME" type="VARCHAR" isMandatory="true" length="50"/> + </db-entity> + <db-entity name="X_SONGAUTHOR"> + <db-attribute name="AUTHOR_ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/> + <db-attribute name="SONG_ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/> + </db-entity> + <obj-entity name="Author" className="org.apache.cayenne.testdo.relationships_many_to_many_join.Author" dbEntityName="X_AUTHOR"> + <obj-attribute name="name" type="java.lang.String" db-attribute-path="AUTHOR_NAME"/> + </obj-entity> + <obj-entity name="Song" className="org.apache.cayenne.testdo.relationships_many_to_many_join.Song" dbEntityName="X_SONG"> + <obj-attribute name="name" type="java.lang.String" db-attribute-path="SONG_NAME"/> + </obj-entity> + <db-relationship name="songAuthor" source="X_AUTHOR" target="X_SONGAUTHOR" toDependentPK="true" toMany="true"> + <db-attribute-pair source="AUTHOR_ID" target="AUTHOR_ID"/> + </db-relationship> + <db-relationship name="songAuthor" source="X_SONG" target="X_SONGAUTHOR" toDependentPK="true" toMany="true"> + <db-attribute-pair source="SONG_ID" target="SONG_ID"/> + </db-relationship> + <db-relationship name="song" source="X_SONGAUTHOR" target="X_SONG"> + <db-attribute-pair source="SONG_ID" target="SONG_ID"/> + </db-relationship> + <db-relationship name="author" source="X_SONGAUTHOR" target="X_AUTHOR"> + <db-attribute-pair source="AUTHOR_ID" target="AUTHOR_ID"/> + </db-relationship> + <obj-relationship name="authors" source="Song" target="Author" collection-type="java.util.Set" deleteRule="Cascade" db-relationship-path="songAuthor.author"/> +</data-map>