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/05/17 07:44:08 UTC
[cayenne] branch master updated: Filter out phantom toMany
relationship changes
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 ec35c17 Filter out phantom toMany relationship changes
ec35c17 is described below
commit ec35c178bbcdf0662823a37c0013fe85caa18e4c
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Fri May 17 10:43:48 2019 +0300
Filter out phantom toMany relationship changes
---
.../cayenne/access/flush/DbRowOpFactory.java | 4 ++--
.../access/flush/DefaultDataDomainFlushAction.java | 23 +++++++++++++++++++++-
.../cayenne/access/flush/ReplacementIdVisitor.java | 2 +-
.../cayenne/access/flush/operation/Values.java | 12 +++++++++++
.../cayenne/CayenneDataObjectRelationshipsIT.java | 18 +++++++++++++++++
5 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DbRowOpFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DbRowOpFactory.java
index 47f4de1..3e967e6 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DbRowOpFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DbRowOpFactory.java
@@ -66,7 +66,7 @@ class DbRowOpFactory {
this.rootRowOpProcessor = new RootRowOpProcessor(this);
}
- private void udpateDiff(ObjectDiff diff) {
+ private void updateDiff(ObjectDiff diff) {
ObjectId id = (ObjectId)diff.getNodeId();
this.diff = diff;
this.descriptor = resolver.getClassDescriptor(id.getEntityName());
@@ -75,7 +75,7 @@ class DbRowOpFactory {
}
Collection<? extends DbRowOp> createRows(ObjectDiff diff) {
- udpateDiff(diff);
+ updateDiff(diff);
DbEntity rootEntity = descriptor.getEntity().getDbEntity();
DbRowOp row = getOrCreate(rootEntity, object.getObjectId(), DbRowOpType.forObject(object));
rootRowOpProcessor.setDiff(diff);
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DefaultDataDomainFlushAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DefaultDataDomainFlushAction.java
index 25511db..14d63a8 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DefaultDataDomainFlushAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/DefaultDataDomainFlushAction.java
@@ -41,6 +41,7 @@ import org.apache.cayenne.access.flush.operation.DbRowOpMerger;
import org.apache.cayenne.access.flush.operation.DbRowOpSorter;
import org.apache.cayenne.access.flush.operation.DbRowOp;
import org.apache.cayenne.access.flush.operation.DbRowOpVisitor;
+import org.apache.cayenne.access.flush.operation.UpdateDbRowOp;
import org.apache.cayenne.graph.CompoundDiff;
import org.apache.cayenne.graph.GraphDiff;
import org.apache.cayenne.log.JdbcEventLogger;
@@ -82,7 +83,8 @@ public class DefaultDataDomainFlushAction implements DataDomainFlushAction {
List<DbRowOp> dbRowOps = createDbRowOps(objectStore, objectStoreGraphDiff);
updateObjectIds(dbRowOps);
List<DbRowOp> deduplicatedOps = mergeSameObjectIds(dbRowOps);
- List<DbRowOp> sortedOps = sort(deduplicatedOps);
+ List<DbRowOp> filteredOps = filterOps(deduplicatedOps);
+ List<DbRowOp> sortedOps = sort(filteredOps);
List<? extends Query> queries = createQueries(sortedOps);
executeQueries(queries);
createReplacementIds(objectStore, afterCommitDiff, sortedOps);
@@ -133,6 +135,12 @@ public class DefaultDataDomainFlushAction implements DataDomainFlushAction {
return dbRowOps;
}
+ protected List<DbRowOp> filterOps(List<DbRowOp> dbRowOps) {
+ // clear phantom update (this can be from insert/delete of arc with transient object)
+ dbRowOps.forEach(row -> row.accept(PhantomDbRowOpCleaner.INSTANCE));
+ return dbRowOps;
+ }
+
/**
* Sort all operations
* @param dbRowOps collection of {@link DbRowOp}
@@ -207,4 +215,17 @@ public class DefaultDataDomainFlushAction implements DataDomainFlushAction {
objectStore.postprocessAfterCommit(afterCommitDiff);
}
+ protected static class PhantomDbRowOpCleaner implements DbRowOpVisitor<Void> {
+
+ protected static final DbRowOpVisitor<Void> INSTANCE = new PhantomDbRowOpCleaner();
+
+ @Override
+ public Void visitUpdate(UpdateDbRowOp dbRow) {
+ //
+ if(dbRow.getChangeId().isTemporary() && !dbRow.getChangeId().isReplacementIdAttached()) {
+ dbRow.getValues().clear();
+ }
+ return null;
+ }
+ }
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ReplacementIdVisitor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ReplacementIdVisitor.java
index 405eec6..a608832 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ReplacementIdVisitor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ReplacementIdVisitor.java
@@ -80,7 +80,7 @@ class ReplacementIdVisitor implements DbRowOpVisitor<Void> {
private void updateId(DbRowOp dbRow) {
ObjectId id = dbRow.getChangeId();
if (!id.isReplacementIdAttached()) {
- if (id.isTemporary()) {
+ if (id == dbRow.getObject().getObjectId() && id.isTemporary()) {
throw new CayenneRuntimeException("PK for the object %s is not set during insert.", dbRow.getObject());
}
return;
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java
index 248d891..4fa8568 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java
@@ -139,6 +139,18 @@ public class Values {
return snapshot == null || snapshot.isEmpty();
}
+ public void clear() {
+ if(snapshot != null) {
+ snapshot.clear();
+ }
+ if(updatedAttributes != null) {
+ updatedAttributes.clear();
+ }
+ if(flattenedIds != null) {
+ flattenedIds.clear();
+ }
+ }
+
public boolean isSameBatch(Values other) {
if(snapshot == null) {
return other.snapshot == null;
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectRelationshipsIT.java b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectRelationshipsIT.java
index 6c13706..72d020e 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectRelationshipsIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectRelationshipsIT.java
@@ -22,6 +22,7 @@ package org.apache.cayenne;
import org.apache.cayenne.access.ToManyList;
import org.apache.cayenne.configuration.server.ServerRuntime;
import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectSelect;
import org.apache.cayenne.test.jdbc.DBHelper;
import org.apache.cayenne.test.jdbc.TableHelper;
import org.apache.cayenne.testdo.testmap.ArtGroup;
@@ -328,4 +329,21 @@ public class CayenneDataObjectRelationshipsIT extends ServerCase {
assertFalse(list.isFault());
}
+
+ @Test
+ public void testTransientInsertAndDeleteOfToManyRelationship() throws Exception {
+ createArtistWithPaintingDataSet();
+
+ Artist artist = ObjectSelect.query(Artist.class).selectOne(context);
+
+ // create and then immediately delete a to-many relationship value
+ Painting object2 = context.newObject(Painting.class);
+ artist.addToPaintingArray(object2);
+ artist.removeFromPaintingArray(object2);
+ context.deleteObject(object2);
+ assertEquals(1, artist.getPaintingArray().size());
+
+ artist.setArtistName("updated artist name"); // this will force the commit to actually execute some SQL
+ context.commitChanges();
+ }
}