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 2021/11/19 13:36:34 UTC

[cayenne] 02/02: CAY-2723 Phantom update of a to-dependent-pk relationship

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

commit cd8f404f6227e4b49b19503d5491152bdc521043
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Fri Nov 19 16:36:13 2021 +0300

    CAY-2723 Phantom update of a to-dependent-pk relationship
---
 .../cayenne/access/flush/DbRowOpFactory.java       |  4 ++
 .../cayenne/access/flush/operation/Qualifier.java  |  2 +-
 .../java/org/apache/cayenne/access/CAY2723IT.java  | 58 ++++++++++++++++++++++
 3 files changed, 63 insertions(+), 1 deletion(-)

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 28fa93d..accf329 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
@@ -94,6 +94,10 @@ class DbRowOpFactory {
     }
 
     private DbRowOp createRow(DbEntity entity, ObjectId id, DbRowOpType type) {
+        // skip phantom nodes, this could be a created and immediately deleted relationship
+        if(store.getNode(id) == null && !id.getEntityName().startsWith("db:")) {
+            return null;
+        }
         switch (type) {
             case INSERT:
                 return new InsertDbRowOp(object, entity, id);
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Qualifier.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Qualifier.java
index 5f17172..0589e0a 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Qualifier.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Qualifier.java
@@ -50,7 +50,7 @@ public class Qualifier {
     public Map<String, Object> getSnapshot() {
         Map<String, Object> idSnapshot = row.getChangeId().getIdSnapshot();
         if(additionalQualifier == null || additionalQualifier.isEmpty()) {
-            return idSnapshot;
+            return new HashMap<>(idSnapshot);
         }
 
         Map<String, Object> qualifier = new HashMap<>(additionalQualifier.size() + idSnapshot.size());
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/CAY2723IT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/CAY2723IT.java
new file mode 100644
index 0000000..b337792
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/CAY2723IT.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.access;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.testdo.testmap.PaintingInfo;
+import org.apache.cayenne.unit.di.DataChannelInterceptor;
+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.assertEquals;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class CAY2723IT extends ServerCase {
+    @Inject
+    private DataContext context;
+
+    @Inject
+    private DataChannelInterceptor queryInterceptor;
+
+    @Test
+    public void phantomToDepPKUpdate() {
+        Painting painting = context.newObject(Painting.class);
+        painting.setPaintingTitle("test_p_123");
+
+        PaintingInfo paintingInfo = context.newObject(PaintingInfo.class);
+        paintingInfo.setTextReview("test_a_123");
+
+        painting.setToPaintingInfo(paintingInfo);
+        painting.setToPaintingInfo(null);
+
+        context.deleteObject(paintingInfo);
+
+        // here should be only single insert of the painting object, but there will be 3 queries in total
+        // (2 for the PK generation + insert)
+        int queryCounter = queryInterceptor.runWithQueryCounter(() -> context.commitChanges());
+        assertEquals(3, queryCounter);
+    }
+}