cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject [1/2] cayenne git commit: CAY-2122 Vertical Inheritance: Cannot Insert Record For Implementing Class with Attribute And Relationship
Date Sat, 08 Oct 2016 14:10:38 GMT
Repository: cayenne
Updated Branches:
  refs/heads/master 42e7b897b -> 377a1ef27


CAY-2122 Vertical Inheritance: Cannot Insert Record For Implementing Class with Attribute
And Relationship

patch by Matt Watson


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/5a76895d
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/5a76895d
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/5a76895d

Branch: refs/heads/master
Commit: 5a76895d01dda45568f564b0f254b637d7f5b239
Parents: 42e7b89
Author: Andrus Adamchik <andrus@objectstyle.com>
Authored: Sat Oct 8 16:43:34 2016 +0300
Committer: Andrus Adamchik <andrus@objectstyle.com>
Committed: Sat Oct 8 17:10:16 2016 +0300

----------------------------------------------------------------------
 .../access/DataDomainFlattenedBucket.java       | 89 +++++++++++++++++---
 .../cayenne/access/DataDomainFlushAction.java   |  2 +-
 .../cayenne/access/VerticalInheritanceIT.java   | 13 +++
 .../testdo/inheritance_vertical/IvBase.java     |  9 ++
 .../testdo/inheritance_vertical/IvImpl.java     |  9 ++
 .../testdo/inheritance_vertical/IvOther.java    |  9 ++
 .../inheritance_vertical/auto/_IvBase.java      | 35 ++++++++
 .../inheritance_vertical/auto/_IvImpl.java      | 38 +++++++++
 .../inheritance_vertical/auto/_IvOther.java     | 42 +++++++++
 .../test/resources/inheritance-vertical.map.xml | 39 +++++++++
 10 files changed, 270 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
index abfd0e8..6ac7db5 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
@@ -27,8 +27,10 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.query.BatchQueryRow;
 import org.apache.cayenne.query.DeleteBatchQuery;
 import org.apache.cayenne.query.InsertBatchQuery;
 import org.apache.cayenne.query.Query;
@@ -41,31 +43,28 @@ import org.apache.cayenne.query.Query;
 class DataDomainFlattenedBucket {
 
     final DataDomainFlushAction parent;
-    final Map<DbEntity, InsertBatchQuery> flattenedInsertQueries;
+    final Map<DbEntity, List<FlattenedArcKey>> insertArcKeys;
     final Map<DbEntity, DeleteBatchQuery> flattenedDeleteQueries;
 
     DataDomainFlattenedBucket(DataDomainFlushAction parent) {
         this.parent = parent;
-        this.flattenedInsertQueries = new HashMap<DbEntity, InsertBatchQuery>();
+        this.insertArcKeys = new HashMap<DbEntity, List<FlattenedArcKey>>();
         this.flattenedDeleteQueries = new HashMap<DbEntity, DeleteBatchQuery>();
     }
 
     boolean isEmpty() {
-        return flattenedInsertQueries.isEmpty() && flattenedDeleteQueries.isEmpty();
+        return insertArcKeys.isEmpty() && flattenedDeleteQueries.isEmpty();
     }
 
-    void addFlattenedInsert(DbEntity flattenedEntity, FlattenedArcKey flattenedArcKey) {
+    void addInsertArcKey(DbEntity flattenedEntity, FlattenedArcKey flattenedArcKey) {
+        List<FlattenedArcKey> arcKeys = insertArcKeys.get(flattenedEntity);
 
-        InsertBatchQuery relationInsertQuery = flattenedInsertQueries.get(flattenedEntity);
-
-        if (relationInsertQuery == null) {
-            relationInsertQuery = new InsertBatchQuery(flattenedEntity, 50);
-            flattenedInsertQueries.put(flattenedEntity, relationInsertQuery);
+        if (arcKeys == null) {
+            arcKeys = new ArrayList<FlattenedArcKey>();
+            insertArcKeys.put(flattenedEntity, arcKeys);
         }
 
-        DataNode node = parent.getDomain().lookupDataNode(flattenedEntity.getDataMap());
-        Map flattenedSnapshot = flattenedArcKey.buildJoinSnapshotForInsert(node);
-        relationInsertQuery.add(flattenedSnapshot);
+        arcKeys.add(flattenedArcKey);
     }
 
     void addFlattenedDelete(DbEntity flattenedEntity, FlattenedArcKey flattenedDeleteInfo)
{
@@ -90,9 +89,50 @@ class DataDomainFlattenedBucket {
         }
     }
 
+    /**
+     * responsible for adding the flattened Insert Queries. Its possible an insert query
for the same DbEntity/ObjectId
+     * already has been added from the insert bucket queries if that Object also has an attribute.
So we want to merge
+     * the data for each insert into a single insert.
+     *
+     * @param queries
+     */
     void appendInserts(Collection<Query> queries) {
-        if (!flattenedInsertQueries.isEmpty()) {
-            queries.addAll(flattenedInsertQueries.values());
+        for (Map.Entry<DbEntity, List<FlattenedArcKey>> entry : insertArcKeys.entrySet())
{
+            DbEntity dbEntity = entry.getKey();
+            List<FlattenedArcKey> flattenedArcKeys = entry.getValue();
+
+            DataNode node = parent.getDomain().lookupDataNode(dbEntity.getDataMap());
+
+            InsertBatchQuery existingQuery = findInsertBatchQuery(queries, dbEntity);
+            InsertBatchQuery newQuery = new InsertBatchQuery(dbEntity, 50);
+
+            for (FlattenedArcKey flattenedArcKey : flattenedArcKeys) {
+                Map<String, Object> snapshot = flattenedArcKey.buildJoinSnapshotForInsert(node);
+
+                if (existingQuery != null) {
+                    BatchQueryRow existingRow = findRowForObjectId(existingQuery.getRows(),
flattenedArcKey.id1.getSourceId());
+                    // todo: do we need to worry about flattenedArcKey.id2 ?
+
+                    if (existingRow != null) {
+                        List<DbAttribute> existingQueryDbAttributes = existingQuery.getDbAttributes();
+
+                        for(int i=0; i < existingQueryDbAttributes.size(); i++) {
+                            Object value = existingRow.getValue(i);
+                            if (value != null) {
+                                snapshot.put(existingQueryDbAttributes.get(i).getName(),
value);
+                            }
+                        }
+                    }
+                }
+
+                newQuery.add(snapshot);
+            }
+
+            if (existingQuery != null) {
+                queries.remove(existingQuery);
+            }
+
+            queries.add(newQuery);
         }
     }
 
@@ -101,4 +141,25 @@ class DataDomainFlattenedBucket {
             queries.addAll(flattenedDeleteQueries.values());
         }
     }
+
+    private InsertBatchQuery findInsertBatchQuery(Collection<Query> queries, DbEntity
dbEntity) {
+        for(Query query : queries) {
+            if (query instanceof InsertBatchQuery) {
+                InsertBatchQuery insertBatchQuery = (InsertBatchQuery)query;
+                if (insertBatchQuery.getDbEntity().equals(dbEntity)) {
+                    return insertBatchQuery;
+                }
+            }
+        }
+        return null;
+    }
+
+    private BatchQueryRow findRowForObjectId(List<BatchQueryRow> rows, ObjectId objectId)
{
+        for (BatchQueryRow row : rows) {
+            if (row.getObjectId().equals(objectId)) {
+                return row;
+            }
+        }
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushAction.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushAction.java
index 75198b2..cebfe67 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushAction.java
@@ -111,7 +111,7 @@ class DataDomainFlushAction {
     }
 
     void addFlattenedInsert(DbEntity flattenedEntity, FlattenedArcKey flattenedInsertInfo)
{
-        flattenedBucket.addFlattenedInsert(flattenedEntity, flattenedInsertInfo);
+        flattenedBucket.addInsertArcKey(flattenedEntity, flattenedInsertInfo);
     }
 
     void addFlattenedDelete(DbEntity flattenedEntity, FlattenedArcKey flattenedDeleteInfo)
{

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index 71f0bf9..c5109a4 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -544,4 +544,17 @@ public class VerticalInheritanceIT extends ServerCase {
 		context.commitChanges();
 	}
 
+	@Test
+	public void testInsertWithAttributeAndRelationship() {
+		IvOther other = context.newObject(IvOther.class);
+		other.setName("other");
+
+		IvImpl impl = context.newObject(IvImpl.class);
+		impl.setName("Impl 1");
+		impl.setAttr1("attr1");
+		impl.setOther(other);
+
+		context.commitChanges();
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvBase.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvBase.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvBase.java
new file mode 100644
index 0000000..b5402e3
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvBase.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.inheritance_vertical;
+
+import org.apache.cayenne.testdo.inheritance_vertical.auto._IvBase;
+
+public abstract class IvBase extends _IvBase {
+
+    private static final long serialVersionUID = 1L; 
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvImpl.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvImpl.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvImpl.java
new file mode 100644
index 0000000..a125df5
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvImpl.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.inheritance_vertical;
+
+import org.apache.cayenne.testdo.inheritance_vertical.auto._IvImpl;
+
+public class IvImpl extends _IvImpl {
+
+    private static final long serialVersionUID = 1L; 
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvOther.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvOther.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvOther.java
new file mode 100644
index 0000000..bf106ac
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/IvOther.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.inheritance_vertical;
+
+import org.apache.cayenne.testdo.inheritance_vertical.auto._IvOther;
+
+public class IvOther extends _IvOther {
+
+    private static final long serialVersionUID = 1L; 
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
new file mode 100644
index 0000000..a7325ff
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
@@ -0,0 +1,35 @@
+package org.apache.cayenne.testdo.inheritance_vertical.auto;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.exp.Property;
+
+/**
+ * Class _IvAbstract 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 _IvBase extends CayenneDataObject {
+
+    private static final long serialVersionUID = 1L; 
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final Property<String> TYPE = new Property<String>("type");
+    public static final Property<String> NAME = new Property<String>("name");
+
+    public void setType(String type) {
+        writeProperty("type", type);
+    }
+    public String getType() {
+        return (String)readProperty("type");
+    }
+
+    public void setName(String name) {
+        writeProperty("name", name);
+    }
+    public String getName() {
+        return (String)readProperty("name");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvImpl.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvImpl.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvImpl.java
new file mode 100644
index 0000000..4e05db3
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvImpl.java
@@ -0,0 +1,38 @@
+package org.apache.cayenne.testdo.inheritance_vertical.auto;
+
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.testdo.inheritance_vertical.IvBase;
+import org.apache.cayenne.testdo.inheritance_vertical.IvOther;
+
+/**
+ * Class _IvConcrete 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 _IvImpl extends IvBase {
+
+    private static final long serialVersionUID = 1L; 
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final Property<String> ATTR1 = new Property<String>("attr1");
+    public static final Property<IvOther> OTHER = new Property<IvOther>("other");
+
+    public void setAttr1(String attr1) {
+        writeProperty("attr1", attr1);
+    }
+    public String getAttr1() {
+        return (String)readProperty("attr1");
+    }
+
+    public void setOther(IvOther other) {
+        setToOneTarget("other", other, true);
+    }
+
+    public IvOther getOther() {
+        return (IvOther)readProperty("other");
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
new file mode 100644
index 0000000..52be2ea
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
@@ -0,0 +1,42 @@
+package org.apache.cayenne.testdo.inheritance_vertical.auto;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.testdo.inheritance_vertical.IvImpl;
+
+import java.util.List;
+
+/**
+ * Class _IvConcrete 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 _IvOther extends CayenneDataObject {
+
+    private static final long serialVersionUID = 1L; 
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final Property<String> NAME = new Property<String>("name");
+    public static final Property<List<IvImpl>> IMPLS = new Property<List<IvImpl>>("impls");
+
+    public void setName(String name) {
+        writeProperty("name", name);
+    }
+    public String getName() {
+        return (String)readProperty("name");
+    }
+
+    public void addToImpls(IvImpl obj) {
+        addToManyTarget("impls", obj, true);
+    }
+    public void removeFromImpls(IvImpl obj) {
+        removeToManyTarget("impls", obj, true);
+    }
+    @SuppressWarnings("unchecked")
+    public List<IvImpl> getImpls() {
+        return (List<IvImpl>)readProperty("impls");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5a76895d/cayenne-server/src/test/resources/inheritance-vertical.map.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/inheritance-vertical.map.xml b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
index 1a48639..ad8fba4 100644
--- a/cayenne-server/src/test/resources/inheritance-vertical.map.xml
+++ b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
@@ -51,6 +51,20 @@
 		<db-attribute name="TYPE" type="CHAR" isMandatory="true" length="1"/>
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 	</db-entity>
+	<db-entity name="IV_OTHER">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="NAME" type="VARCHAR" length="100"/>
+	</db-entity>
+	<db-entity name="IV_BASE">
+		<db-attribute name="TYPE" type="CHAR" isMandatory="true" length="1"/>
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="NAME" type="VARCHAR" length="100" isMandatory="true"/>
+	</db-entity>
+	<db-entity name="IV_IMPL">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="ATTR1" type="VARCHAR" length="100" isMandatory="true"/>
+		<db-attribute name="OTHER_ID" type="INTEGER" isMandatory="true"/>
+	</db-entity>
 	<obj-entity name="IvConcrete" superEntityName="IvAbstract" className="org.apache.cayenne.testdo.inheritance_vertical.IvConcrete">
 		<qualifier><![CDATA[type = "S"]]></qualifier>
 		<obj-attribute name="name" type="java.lang.String" db-attribute-path="concrete.NAME"/>
@@ -96,6 +110,17 @@
 		<obj-attribute name="sub2Attr" type="java.lang.String" db-attribute-path="sub2.SUB2_ATTR"/>
 		<obj-attribute name="sub2Name" type="java.lang.String" db-attribute-path="sub2.SUB2_NAME"/>
 	</obj-entity>
+	<obj-entity name="IvOther" className="org.apache.cayenne.testdo.inheritance_vertical.IvOther"
dbEntityName="IV_OTHER">
+		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+	</obj-entity>
+	<obj-entity name="IvBase" abstract="true" className="org.apache.cayenne.testdo.inheritance_vertical.IvBase"
dbEntityName="IV_BASE">
+		<obj-attribute name="type" type="java.lang.String" db-attribute-path="TYPE"/>
+		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+	</obj-entity>
+	<obj-entity name="IvImpl" superEntityName="IvBase" className="org.apache.cayenne.testdo.inheritance_vertical.IvImpl">
+		<qualifier><![CDATA[type = "I"]]></qualifier>
+		<obj-attribute name="attr1" type="java.lang.String" db-attribute-path="impl.ATTR1"/>
+	</obj-entity>
 	<db-relationship name="abstract" source="IV_CONCRETE" target="IV_ABSTRACT" toMany="false">
 		<db-attribute-pair source="ID" target="ID"/>
 	</db-relationship>
@@ -144,7 +169,21 @@
 	<db-relationship name="master" source="IV_SUB2" target="IV_ROOT" toMany="false">
 		<db-attribute-pair source="ID" target="ID"/>
 	</db-relationship>
+	<db-relationship name="impl" source="IV_BASE" target="IV_IMPL" toDependentPK="true" toMany="false">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
+	<db-relationship name="base" source="IV_IMPL" target="IV_BASE" toMany="false">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
+	<db-relationship name="other" source="IV_IMPL" target="IV_OTHER" toMany="false">
+		<db-attribute-pair source="OTHER_ID" target="ID"/>
+	</db-relationship>
+	<db-relationship name="impls" source="IV_OTHER" target="IV_IMPL" toMany="true">
+		<db-attribute-pair source="ID" target="OTHER_ID"/>
+	</db-relationship>
 	<obj-relationship name="x" source="Iv2Sub1" target="Iv2X" deleteRule="Nullify" db-relationship-path="sub1.x"/>
 	<obj-relationship name="parent" source="IvConcrete" target="IvConcrete" deleteRule="Nullify"
db-relationship-path="parent"/>
 	<obj-relationship name="children" source="IvConcrete" target="IvConcrete" deleteRule="Deny"
db-relationship-path="children"/>
+	<obj-relationship name="other" source="IvImpl" target="IvOther" deleteRule="Nullify"
db-relationship-path="impl.other"/>
+	<obj-relationship name="impls" source="IvOther" target="IvImpl" deleteRule="Deny" db-relationship-path="impls.base"/>
 </data-map>


Mime
View raw message