From a5d25626f04f128df28a224dc2466e7a3852278e Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Tue, 9 Aug 2022 11:46:08 +0200 Subject: [PATCH] Skip managed tables in M2M updates --- .../server/deploy/BeanDescriptor.java | 7 ------- .../server/deploy/BeanDescriptorManager.java | 8 ++++++-- .../server/deploy/BeanPropertyAssocMany.java | 10 +++++++--- .../deploy/meta/DeployBeanDescriptor.java | 7 +++++++ .../meta/DeployBeanPropertyAssocMany.java | 4 ++++ .../test/java/org/tests/model/m2m/MnyNode.java | 2 +- .../org/tests/model/m2m/TestM2MWithWhere.java | 17 +++++++++++++++++ 7 files changed, 42 insertions(+), 13 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 08804a53d..6bfe5227e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -1934,13 +1934,6 @@ public class BeanDescriptor implements BeanType, STreeType, SpiBeanType { return owner.descriptor(otherType); } - /** - * Returns true, if the table is managed (i.e. an existing m2m relation). - */ - public boolean isTableManaged(String tableName) { - return owner.isTableManaged(tableName); - } - /** * Return the order column property. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index f9893cd30..5aa8adb96 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -89,6 +89,8 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy private final String serverName; private final List> elementDescriptors = new ArrayList<>(); private final Map beanTableMap = new HashMap<>(); + + private final Set managedTables = new HashSet<>(); private final Map> descMap = new HashMap<>(); private final Map> descQueueMap = new HashMap<>(); private final Map> beanManagerMap = new HashMap<>(); @@ -422,8 +424,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy @Override public boolean isTableManaged(String tableName) { - return tableToDescMap.get(tableName.toLowerCase()) != null - || tableToViewDescMap.get(tableName.toLowerCase()) != null; + return managedTables.contains(tableName); } /** @@ -691,6 +692,9 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy for (DeployBeanInfo info : deployInfoMap.values()) { BeanTable beanTable = createBeanTable(info); beanTableMap.put(beanTable.getBeanType().getName(), beanTable); + if (beanTable.getBaseTable() != null) { + managedTables.add(beanTable.getBaseTable()); + } } // register non-id embedded beans (after bean tables are created) for (DeployBeanInfo info : embeddedBeans) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 81a5f4632..13ceb7aa2 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -36,6 +36,8 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST * Join for manyToMany intersection table. */ private final TableJoin intersectionJoin; + + private final boolean tableManaged; private final String intersectionPublishTable; private final String intersectionDraftTable; private final boolean orphanRemoval; @@ -98,9 +100,11 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST this.fetchOrderBy = deploy.getFetchOrderBy(); this.intersectionJoin = deploy.createIntersectionTableJoin(); if (intersectionJoin != null) { + this.tableManaged = deploy.isTableManaged(); this.intersectionPublishTable = intersectionJoin.getTable(); this.intersectionDraftTable = deploy.getIntersectionDraftTable(); } else { + this.tableManaged = false; this.intersectionPublishTable = null; this.intersectionDraftTable = null; } @@ -912,11 +916,11 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST // Note ManyToMany always included as we always 'save' // the relationship via insert/delete of intersection table // REMOVALS means including PrivateOwned relationships - return cascadeInfo.isSave() || hasJoinTable() || ModifyListenMode.REMOVALS == modifyListenMode; + return cascadeInfo.isSave() || (hasJoinTable() && !tableManaged) || ModifyListenMode.REMOVALS == modifyListenMode; } public boolean isIncludeCascadeDelete() { - return cascadeInfo.isDelete() || hasJoinTable() || ModifyListenMode.REMOVALS == modifyListenMode; + return cascadeInfo.isDelete() || (hasJoinTable() && !tableManaged) || ModifyListenMode.REMOVALS == modifyListenMode; } boolean isCascadeDeleteEscalate() { @@ -1050,7 +1054,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST public boolean createJoinTable() { if (hasJoinTable() && mappedBy() == null) { // only create on other 'owning' side - return !descriptor.isTableManaged(intersectionJoin.getTable()); + return !tableManaged; } else { return false; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index a69d111ca..380537671 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -63,6 +63,13 @@ public class DeployBeanDescriptor implements DeployBeanDescriptorMeta { private static final Map EMPTY_RAW_MAP = new HashMap<>(); + /** + * Returns true, if the table is managed (i.e. an existing m2m relation). + */ + public boolean isTableManaged(String tableName) { + return manager.isTableManaged(tableName); + } + private static class PropOrder implements Comparator { @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java index c201308e2..edd41640c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java @@ -113,6 +113,10 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { } } + public boolean isTableManaged() { + return intersectionJoin != null && desc.isTableManaged(intersectionJoin.getTable()); + } + /** * Create the immutable version of the inverse join. */ diff --git a/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java b/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java index fabb58040..0e0fbd039 100644 --- a/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java +++ b/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java @@ -16,7 +16,7 @@ public class MnyNode { String name; - @ManyToMany + @ManyToMany(cascade = CascadeType.REFRESH) @JoinTable(name = "mny_edge", joinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id")) diff --git a/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java b/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java index d9ac37ffc..a375f9a2e 100644 --- a/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java +++ b/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java @@ -18,6 +18,23 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class TestM2MWithWhere extends BaseTestCase { + @Test + public void testModify() throws Exception { + createTestData(); + MnyNode node = DB.find(MnyNode.class, 1); + node.setName("fooBarBaz"); + MnyNode removed = node.getAllRelations().remove(0); + LoggedSql.start(); + DB.save(node); + List sql = LoggedSql.stop(); + sql.forEach(System.out::println); + + node.getAllRelations().add(removed); + LoggedSql.start(); + DB.save(node); + sql = LoggedSql.stop(); + sql.forEach(System.out::println); + } @Test public void testQuery() throws Exception { createTestData();