From 5a73c85e6eab847037c83ea53d5eabbe11862e78 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Mon, 1 Mar 2021 18:36:49 +1300 Subject: [PATCH 1/2] Refactor internals - SqlTreeNodeBean add derived readIdNormal + private methods This is no effective change --- .../server/query/SqlTreeNodeBean.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index 51ed19d32..011d9f1a7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.query; -import io.ebean.Version; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; import io.ebean.bean.EntityBeanIntercept; @@ -16,7 +15,6 @@ import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.id.IdBinder; import java.sql.SQLException; -import java.sql.Timestamp; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -56,6 +54,7 @@ class SqlTreeNodeBean implements SqlTreeNode { * False if report bean and has no id property. */ final boolean readId; + private final boolean readIdNormal; private final boolean disableLazyLoad; @@ -120,7 +119,8 @@ class SqlTreeNodeBean implements SqlTreeNode { boolean aggregationRoot = props.isAggregationRoot(); // the bean has an Id property and we want to use it this.readId = !aggregationRoot && withId && desc.hasId(); - this.disableLazyLoad = disableLazyLoad || !readId || desc.isRawSqlBased() || temporalVersions; + this.readIdNormal = readId && !temporalVersions; + this.disableLazyLoad = disableLazyLoad || !readIdNormal || desc.isRawSqlBased(); this.partialObject = props.isPartialObject(); this.properties = props.getProps(); this.children = myChildren == null ? NO_CHILDREN : myChildren.toArray(new SqlTreeNode[0]); @@ -253,7 +253,7 @@ class SqlTreeNodeBean implements SqlTreeNode { this.parentBean = parentBean; } - void initLazyParent() throws SQLException { + private void initLazyParent() throws SQLException { if (lazyLoadParentIdBinder != null) { lazyLoadParentId = lazyLoadParentIdBinder.read(ctx); } @@ -265,12 +265,12 @@ class SqlTreeNodeBean implements SqlTreeNode { localIdBinder = idBinder; } - void initPersistenceContext() { + private void initPersistenceContext() { queryMode = ctx.getQueryMode(); - persistenceContext = (!readId || temporalVersions) ? null : ctx.getPersistenceContext(); + persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext(); } - void readId() throws SQLException { + private void readId() throws SQLException { if (readId) { id = localIdBinder.readSet(ctx, localBean); if (id == null) { @@ -311,7 +311,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - void initSqlLoadBean() { + private void initSqlLoadBean() { ctx.setCurrentPrefix(prefix, pathMap); ctx.propagateState(localBean); sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode); @@ -323,7 +323,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - void loadChildren() throws SQLException { + private void loadChildren() throws SQLException { //boolean lazyLoadMany = false; if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) { // batch lazy load many into existing contextBean @@ -338,18 +338,18 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - boolean isLazyLoadManyRoot() { + private boolean isLazyLoadManyRoot() { return queryMode == Mode.LAZYLOAD_MANY && isRoot(); } - EntityBean getContextBean() { + private EntityBean getContextBean() { return contextBean; } - void postLoad() { + private void postLoad() { if (!lazyLoadMany && localBean != null) { ctx.setCurrentPrefix(prefix, pathMap); - if (readId && !temporalVersions) { + if (readIdNormal) { createListProxies(); } if (temporalMode == SpiQuery.TemporalMode.DRAFT) { @@ -411,15 +411,15 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - void setBeanToParent() { + private void setBeanToParent() { if (parentBean != null) { // set this back to the parentBean nodeBeanProp.setValue(parentBean, contextBean); } } - EntityBean complete() { - if (!readId || temporalVersions) { + private EntityBean complete() { + if (!readIdNormal) { // a bean with no Id (never found in context) if (lazyLoadParentId != null) { ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId); @@ -434,7 +434,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - void initialise() throws SQLException { + private void initialise() throws SQLException { initLazyParent(); initBeanType(); initPersistenceContext(); From 297c1d7abb2b28bb5457a9f51e14644159a52193 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Mon, 1 Mar 2021 20:27:50 +1300 Subject: [PATCH 2/2] #2179 - Improved fix for (2179) Fetch on nested one-to-many collections results in duplicates The improvement here is that SqlTreeNodeManyRoot uses load and isContextBean() so that it only checks if the collection already contains the detailBean if the detailBean was already in the persistence context (aka not newly loaded and added). The vast majority case is that detailBean is loaded fresh so for the common case we can skip the extra collection contains() check. --- .../main/java/io/ebean/common/BeanSet.java | 5 +- .../server/query/SqlTreeNodeBean.java | 48 ++++++++++++------- .../server/query/SqlTreeNodeManyRoot.java | 13 ++--- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/common/BeanSet.java b/ebean-api/src/main/java/io/ebean/common/BeanSet.java index 91f0ae672..880ece106 100644 --- a/ebean-api/src/main/java/io/ebean/common/BeanSet.java +++ b/ebean-api/src/main/java/io/ebean/common/BeanSet.java @@ -70,9 +70,8 @@ public final class BeanSet extends AbstractBeanCollection implements Set