From f4ef6d33c218805c501d0e25aa8f3440712a11f6 Mon Sep 17 00:00:00 2001
From: Iliya Ivanov
Date: Wed, 3 Dec 2025 20:00:55 +0200
Subject: [PATCH 1/6] Make embeddable diggable
---
.../server/deploy/BeanDescriptor.java | 10 ++--
.../server/deploy/BeanPropertyAssoc.java | 6 ---
.../server/deploy/BeanPropertyAssocOne.java | 16 +++----
.../server/el/ElPropertyChain.java | 26 ++++------
.../server/el/ElPropertyChainBuilder.java | 22 +++------
.../server/query/SqlTreeAlias.java | 47 ++++++++++---------
.../server/query/SqlTreeBuilder.java | 8 +++-
.../query/SqlTreeNodeManyWhereJoin.java | 3 ++
8 files changed, 66 insertions(+), 72 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 6b580119ff..de1513a103 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
@@ -2362,6 +2362,12 @@ ElPropertyValue buildElGetValue(String propName, ElPropertyChainBuilder chain, b
if (assocProp == null) {
return null;
}
+ // this method is an entry-point, although it introduces recursive calls via
+ // buildElPropertyValue -> createElPropertyValue -> buildElGetValue (back to here)
+ // it seams we can initialize ElPropertyChainBuilder at this point and skip further checks.
+ if (chain == null) {
+ chain = new ElPropertyChainBuilder(propName);
+ }
String remainder = propName.substring(basePos + 1);
return assocProp.buildElPropertyValue(propName, remainder, chain, propertyDeploy);
}
@@ -2373,9 +2379,7 @@ ElPropertyValue buildElGetValue(String propName, ElPropertyChainBuilder chain, b
if (property == null) {
throw new PersistenceException("No property found for [" + propName + "] in expression " + chain.expression());
}
- if (property.containsMany()) {
- chain.setContainsMany();
- }
+
return chain.add(property).build();
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java
index ef10e0dbc6..966b2e3094 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java
@@ -161,13 +161,7 @@ public boolean hasForeignKeyIndex() {
ElPropertyValue createElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
// associated or embedded bean
BeanDescriptor> embDesc = targetDescriptor();
- if (chain == null) {
- chain = new ElPropertyChainBuilder(isEmbedded(), propName);
- }
chain.add(this);
- if (containsMany()) {
- chain.setContainsMany();
- }
return embDesc.buildElGetValue(remainder, chain, propertyDeploy);
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
index 5bb4fe2c02..544a31946c 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
@@ -210,17 +210,17 @@ Object naturalKeyVal(Map values) {
@Override
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
if (embedded) {
- BeanProperty embProp = embeddedPropsMap.get(remainder);
+ String embName = remainder;
+ int basePos = remainder.indexOf('.');
+ if (basePos > -1) {
+ embName = remainder.substring(0, basePos);
+ }
+ BeanProperty embProp = embeddedPropsMap.get(embName);
+
if (embProp == null) {
- String msg = "Embedded Property " + remainder + " not found in " + fullName();
+ String msg = "Embedded Property " + embName + " not found in " + fullName();
throw new PersistenceException(msg);
}
- if (chain == null) {
- chain = new ElPropertyChainBuilder(true, propName);
- }
- chain.add(this);
- chain.setEmbedded(true);
- return chain.add(embProp).build();
}
return createElPropertyValue(propName, remainder, chain, propertyDeploy);
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChain.java b/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChain.java
index 12d376bed0..f023764346 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChain.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChain.java
@@ -37,38 +37,32 @@ public final class ElPropertyChain implements ElPropertyValue {
private final ScalarType> scalarType;
private final ElPropertyValue lastElPropertyValue;
- public ElPropertyChain(boolean containsMany, boolean embedded, String expression, ElPropertyValue[] chain) {
- this.containsMany = containsMany;
+ public ElPropertyChain(String expression, boolean containsMany, ElPropertyValue chain[]) {
this.chain = chain;
this.expression = expression;
+ this.containsMany = containsMany;
+
int dotPos = expression.lastIndexOf('.');
if (dotPos > -1) {
this.name = expression.substring(dotPos + 1);
- if (embedded) {
- int embPos = expression.lastIndexOf('.', dotPos - 1);
- this.prefix = embPos == -1 ? null : expression.substring(0, embPos);
-
- } else {
- this.prefix = expression.substring(0, dotPos);
- }
+ this.prefix = expression.substring(0, dotPos);
} else {
this.prefix = null;
this.name = expression;
}
- this.assocId = chain[chain.length - 1].isAssocId();
-
- this.last = chain.length - 1;
- this.lastBeanProperty = chain[chain.length - 1].beanProperty();
+ this.last = this.chain.length - 1;
+ this.lastElPropertyValue = this.chain[this.last];
+ this.assocId = this.lastElPropertyValue.isAssocId();
+ this.lastBeanProperty = lastElPropertyValue.beanProperty();
if (lastBeanProperty != null) {
this.scalarType = lastBeanProperty.scalarType();
} else {
// case for nested compound type (non-scalar)
this.scalarType = null;
}
- this.lastElPropertyValue = chain[chain.length - 1];
- this.placeHolder = placeHolder(prefix, lastElPropertyValue, false);
- this.placeHolderEncrypted = placeHolder(prefix, lastElPropertyValue, true);
+ this.placeHolder = placeHolder(this.prefix, lastElPropertyValue, false);
+ this.placeHolderEncrypted = placeHolder(this.prefix, lastElPropertyValue, true);
}
@Override
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChainBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChainBuilder.java
index 409f17bc70..d372330333 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChainBuilder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/el/ElPropertyChainBuilder.java
@@ -17,14 +17,12 @@ public final class ElPropertyChainBuilder {
private final String expression;
private final List chain = new ArrayList<>();
- private boolean embedded;
- private boolean containsMany;
+ private boolean containsMany = false;
/**
* Create with the original expression.
*/
- public ElPropertyChainBuilder(boolean embedded, String expression) {
- this.embedded = embedded;
+ public ElPropertyChainBuilder(String expression) {
this.expression = expression;
}
@@ -32,10 +30,6 @@ public boolean isContainsMany() {
return containsMany;
}
- public void setContainsMany() {
- this.containsMany = true;
- }
-
public String expression() {
return expression;
}
@@ -48,6 +42,9 @@ public ElPropertyChainBuilder add(ElPropertyValue element) {
throw new NullPointerException("element null in expression " + expression);
}
chain.add(element);
+ if (element.containsMany()) {
+ containsMany = true;
+ }
return this;
}
@@ -55,13 +52,6 @@ public ElPropertyChainBuilder add(ElPropertyValue element) {
* Build the immutable ElGetChain from the build information.
*/
public ElPropertyChain build() {
- return new ElPropertyChain(containsMany, embedded, expression, chain.toArray(new ElPropertyValue[0]));
- }
-
- /**
- * Permits to set whole chain as embedded when the leaf is embedded
- */
- public void setEmbedded(boolean embedded) {
- this.embedded = embedded;
+ return new ElPropertyChain(expression, containsMany, chain.toArray(new ElPropertyValue[0]));
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
index 3a5e7bdc7d..06f1f4a090 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
@@ -4,7 +4,6 @@
import io.ebeaninternal.api.SpiQuery;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -16,7 +15,8 @@ final class SqlTreeAlias {
private final SpiQuery.TemporalMode temporalMode;
private final TreeSet joinProps = new TreeSet<>();
- private HashSet embeddedPropertyJoins;
+ // embedded property as key, and true if many-where-property
+ private HashMap embeddedPropertyJoins;
private final TreeSet manyWhereJoinProps = new TreeSet<>();
private final HashMap aliasMap = new HashMap<>();
private final HashMap manyWhereAliasMap = new HashMap<>();
@@ -32,19 +32,19 @@ final class SqlTreeAlias {
/**
* Add joins to support where predicates
*/
- void addManyWhereJoins(Set manyWhereJoins) {
+ void addManyWhereJoins(Set manyWhereJoins, STreeType desc) {
if (manyWhereJoins != null) {
for (String include : manyWhereJoins) {
- addPropertyJoin(include, manyWhereJoinProps);
+ addPropertyJoin(include, manyWhereJoinProps, desc, true);
}
}
}
- private void addEmbeddedPropertyJoin(String embProp) {
+ private void addEmbeddedPropertyJoin(String embProp, Boolean isManyWhere) {
if (embeddedPropertyJoins == null) {
- embeddedPropertyJoins = new HashSet<>();
+ embeddedPropertyJoins = new HashMap<>();
}
- embeddedPropertyJoins.add(embProp);
+ embeddedPropertyJoins.put(embProp, isManyWhere);
}
/**
@@ -53,21 +53,21 @@ private void addEmbeddedPropertyJoin(String embProp) {
public void addJoin(Set propJoins, STreeType desc) {
if (propJoins != null) {
for (String propJoin : propJoins) {
- if (desc.isEmbeddedPath(propJoin)) {
- addEmbeddedPropertyJoin(propJoin);
- } else {
- addPropertyJoin(propJoin, joinProps);
- }
+ addPropertyJoin(propJoin, joinProps, desc, false);
}
}
}
- private void addPropertyJoin(String include, TreeSet set) {
- if (set.add(include)) {
- String[] split = SplitName.split(include);
- if (split[0] != null) {
- addPropertyJoin(split[0], set);
- }
+ private void addPropertyJoin(String include, TreeSet set, STreeType desc, Boolean isManyWhere) {
+ if (include == null) {
+ return;
+ }
+ String[] split = SplitName.split(include);
+ if (desc.isEmbeddedPath(include)) {
+ addEmbeddedPropertyJoin(include, isManyWhere);
+ addPropertyJoin(split[0], set, desc, isManyWhere);
+ } else if (set.add(include)) {
+ addPropertyJoin(split[0], set, desc, isManyWhere);
}
}
@@ -86,11 +86,14 @@ void buildAlias() {
private void mapEmbeddedPropertyAlias() {
if (embeddedPropertyJoins != null) {
- for (String propJoin : embeddedPropertyJoins) {
- String[] split = SplitName.split(propJoin);
+ for (Map.Entry propJoin : embeddedPropertyJoins.entrySet()) {
+ String[] split = SplitName.split(propJoin.getKey());
// the table alias of the parent path
- String alias = tableAlias(split[0]);
- aliasMap.put(propJoin, alias);
+ if (Boolean.TRUE.equals(propJoin.getValue())) {
+ manyWhereAliasMap.put(propJoin.getKey(), tableAliasManyWhere(split[0]));
+ } else {
+ aliasMap.put(propJoin.getKey(), tableAlias(split[0]));
+ }
}
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
index 9b828fa9db..90b84ce3a3 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -220,7 +220,7 @@ private SqlTreeNode buildRootNode(STreeType desc) {
if (!rawSql) {
alias.addJoin(queryDetail.getFetchPaths(), desc);
alias.addJoin(predicates.predicateIncludes(), desc);
- alias.addManyWhereJoins(manyWhereJoins.propertyNames());
+ alias.addManyWhereJoins(manyWhereJoins.propertyNames(), desc);
// build set of table alias
alias.buildAlias();
predicates.parseTableAlias(alias);
@@ -681,6 +681,12 @@ private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeEx
// parent already handled by select
return childJoin;
}
+ if (desc.isEmbeddedPath(parentPropertyName)) {
+ // digging in embedded property
+ // so we have to join parent property path
+ includeProp = parentPropertyName;
+ continue;
+ }
SqlTreeNodeExtraJoin parentJoin = joinRegister.get(parentPropertyName);
if (parentJoin == null) {
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
index ada05c4c97..052d71055e 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java
@@ -83,6 +83,9 @@ public void appendFrom(DbSqlContext ctx, SqlJoinType currentJoinType) {
* intersection table if this is a ManyToMany node.
*/
private void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
+ if (nodeBeanProp.isEmbedded()) {
+ return;
+ }
String alias = ctx.tableAliasManyWhere(prefix);
String parentAlias = ctx.tableAliasManyWhere(parentPrefix);
From 994af7bcf1a75fa4e3414908237a7c7945fd5ec7 Mon Sep 17 00:00:00 2001
From: Iliya Ivanov
Date: Sun, 7 Dec 2025 10:09:29 +0200
Subject: [PATCH 2/6] WIP
---
.../ebeaninternal/server/query/SqlTreeBuilder.java | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
index 90b84ce3a3..984c13804f 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -649,14 +649,19 @@ private void createExtraJoin(String includeProp) {
* Create a SqlTreeNodeExtraJoin, register and return it.
*/
private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
+ if (propertyName == null) {
+ return null;
+ }
+ if (desc.isEmbeddedPath(propertyName)) {
+ return createJoinLeaf(SplitName.split(propertyName)[0]);
+ }
ExtraJoin extra = desc.extraJoin(propertyName);
if (extra == null) {
return null;
- } else {
- SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.property(), extra.isContainsMany(), temporalMode);
- joinRegister.put(propertyName, extraJoin);
- return extraJoin;
}
+ SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.property(), extra.isContainsMany(), temporalMode);
+ joinRegister.put(propertyName, extraJoin);
+ return extraJoin;
}
/**
From 5fd6921c535d10f66d231ae1840611b0c433b3a3 Mon Sep 17 00:00:00 2001
From: Iliya Ivanov
Date: Sun, 7 Dec 2025 10:17:29 +0200
Subject: [PATCH 3/6] WIP
---
.../io/ebeaninternal/server/query/SqlTreeBuilder.java | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
index 984c13804f..735e6aa27c 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -653,6 +653,8 @@ private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
return null;
}
if (desc.isEmbeddedPath(propertyName)) {
+ // digging in embedded property
+ // so we have to join parent property path
return createJoinLeaf(SplitName.split(propertyName)[0]);
}
ExtraJoin extra = desc.extraJoin(propertyName);
@@ -686,12 +688,6 @@ private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeEx
// parent already handled by select
return childJoin;
}
- if (desc.isEmbeddedPath(parentPropertyName)) {
- // digging in embedded property
- // so we have to join parent property path
- includeProp = parentPropertyName;
- continue;
- }
SqlTreeNodeExtraJoin parentJoin = joinRegister.get(parentPropertyName);
if (parentJoin == null) {
From 348aca1a4b7d6170a883c6bf07f21848637e0527 Mon Sep 17 00:00:00 2001
From: Iliya Ivanov
Date: Sun, 7 Dec 2025 12:03:46 +0200
Subject: [PATCH 4/6] WIP
---
.../ebeaninternal/server/deploy/BeanDescriptor.java | 4 +---
.../ebeaninternal/server/query/SqlTreeBuilder.java | 13 +++----------
2 files changed, 4 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 de1513a103..b90db30163 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
@@ -2828,9 +2828,7 @@ public ExtraJoin extraJoin(String propertyPath) {
BeanProperty beanProperty = elGetValue.beanProperty();
if (beanProperty instanceof BeanPropertyAssoc>) {
BeanPropertyAssoc> assocProp = (BeanPropertyAssoc>) beanProperty;
- if (!assocProp.isEmbedded()) {
- return new ExtraJoin(assocProp, elGetValue.containsMany());
- }
+ return new ExtraJoin(assocProp, elGetValue.containsMany());
}
}
return null;
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
index 735e6aa27c..b6a3a6340a 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -638,7 +638,7 @@ private void createExtraJoin(String includeProp) {
// find root of this extra join... linking back to the
// parents (creating the tree) as it goes.
- SqlTreeNodeExtraJoin root = findExtraJoinRoot(includeProp, extraJoin);
+ SqlTreeNodeExtraJoin root = findExtraJoinRoot(extraJoin);
// register the root because these are the only ones we
// return back.
rootRegister.put(root.name(), root);
@@ -649,14 +649,6 @@ private void createExtraJoin(String includeProp) {
* Create a SqlTreeNodeExtraJoin, register and return it.
*/
private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
- if (propertyName == null) {
- return null;
- }
- if (desc.isEmbeddedPath(propertyName)) {
- // digging in embedded property
- // so we have to join parent property path
- return createJoinLeaf(SplitName.split(propertyName)[0]);
- }
ExtraJoin extra = desc.extraJoin(propertyName);
if (extra == null) {
return null;
@@ -674,7 +666,8 @@ private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
* not specified and is implicitly created.
*
*/
- private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeExtraJoin childJoin) {
+ private SqlTreeNodeExtraJoin findExtraJoinRoot(SqlTreeNodeExtraJoin childJoin) {
+ String includeProp = childJoin.name();
while (true) {
int dotPos = includeProp.lastIndexOf('.');
if (dotPos == -1) {
From 5c3212b0b27889ffe85da20533d063cd67cd0a1a Mon Sep 17 00:00:00 2001
From: Iliya Ivanov
Date: Sun, 7 Dec 2025 14:33:34 +0200
Subject: [PATCH 5/6] WIP
---
.../server/query/SqlTreeAlias.java | 52 +++++++++----------
.../server/query/SqlTreeBuilder.java | 12 ++---
2 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
index 06f1f4a090..6a13a74e93 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
@@ -4,6 +4,7 @@
import io.ebeaninternal.api.SpiQuery;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -15,8 +16,7 @@ final class SqlTreeAlias {
private final SpiQuery.TemporalMode temporalMode;
private final TreeSet joinProps = new TreeSet<>();
- // embedded property as key, and true if many-where-property
- private HashMap embeddedPropertyJoins;
+ private HashSet embeddedPropertyJoins;
private final TreeSet manyWhereJoinProps = new TreeSet<>();
private final HashMap aliasMap = new HashMap<>();
private final HashMap manyWhereAliasMap = new HashMap<>();
@@ -35,39 +35,42 @@ final class SqlTreeAlias {
void addManyWhereJoins(Set manyWhereJoins, STreeType desc) {
if (manyWhereJoins != null) {
for (String include : manyWhereJoins) {
- addPropertyJoin(include, manyWhereJoinProps, desc, true);
+ addPropertyJoin(include, manyWhereJoinProps, desc);
}
}
}
- private void addEmbeddedPropertyJoin(String embProp, Boolean isManyWhere) {
+ private boolean addEmbeddedPropertyJoin(String embProp) {
if (embeddedPropertyJoins == null) {
- embeddedPropertyJoins = new HashMap<>();
+ embeddedPropertyJoins = new HashSet<>();
}
- embeddedPropertyJoins.put(embProp, isManyWhere);
+ return embeddedPropertyJoins.add(embProp);
}
/**
* Add joins.
*/
public void addJoin(Set propJoins, STreeType desc) {
- if (propJoins != null) {
- for (String propJoin : propJoins) {
- addPropertyJoin(propJoin, joinProps, desc, false);
- }
+ if (propJoins == null) {
+ return;
+ }
+ for (String propJoin : propJoins) {
+ addPropertyJoin(propJoin, joinProps, desc);
}
}
- private void addPropertyJoin(String include, TreeSet set, STreeType desc, Boolean isManyWhere) {
- if (include == null) {
- return;
- }
- String[] split = SplitName.split(include);
+ private void addPropertyJoin(String include, TreeSet set, STreeType desc) {
+ boolean added = false;
if (desc.isEmbeddedPath(include)) {
- addEmbeddedPropertyJoin(include, isManyWhere);
- addPropertyJoin(split[0], set, desc, isManyWhere);
- } else if (set.add(include)) {
- addPropertyJoin(split[0], set, desc, isManyWhere);
+ added = addEmbeddedPropertyJoin(include);
+ } else {
+ added = set.add(include);
+ }
+ if (added) {
+ String[] split = SplitName.split(include);
+ if (split[0] != null) {
+ addPropertyJoin(split[0], set, desc);
+ }
}
}
@@ -86,14 +89,11 @@ void buildAlias() {
private void mapEmbeddedPropertyAlias() {
if (embeddedPropertyJoins != null) {
- for (Map.Entry propJoin : embeddedPropertyJoins.entrySet()) {
- String[] split = SplitName.split(propJoin.getKey());
+ for (String propJoin : embeddedPropertyJoins) {
+ String[] split = SplitName.split(propJoin);
// the table alias of the parent path
- if (Boolean.TRUE.equals(propJoin.getValue())) {
- manyWhereAliasMap.put(propJoin.getKey(), tableAliasManyWhere(split[0]));
- } else {
- aliasMap.put(propJoin.getKey(), tableAlias(split[0]));
- }
+ String alias = tableAlias(split[0]);
+ aliasMap.put(propJoin, alias);
}
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
index b6a3a6340a..7e52df477c 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -638,7 +638,7 @@ private void createExtraJoin(String includeProp) {
// find root of this extra join... linking back to the
// parents (creating the tree) as it goes.
- SqlTreeNodeExtraJoin root = findExtraJoinRoot(extraJoin);
+ SqlTreeNodeExtraJoin root = findExtraJoinRoot(includeProp, extraJoin);
// register the root because these are the only ones we
// return back.
rootRegister.put(root.name(), root);
@@ -652,10 +652,11 @@ private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
ExtraJoin extra = desc.extraJoin(propertyName);
if (extra == null) {
return null;
+ } else {
+ SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.property(), extra.isContainsMany(), temporalMode);
+ joinRegister.put(propertyName, extraJoin);
+ return extraJoin;
}
- SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.property(), extra.isContainsMany(), temporalMode);
- joinRegister.put(propertyName, extraJoin);
- return extraJoin;
}
/**
@@ -666,8 +667,7 @@ private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
* not specified and is implicitly created.
*
*/
- private SqlTreeNodeExtraJoin findExtraJoinRoot(SqlTreeNodeExtraJoin childJoin) {
- String includeProp = childJoin.name();
+ private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeExtraJoin childJoin) {
while (true) {
int dotPos = includeProp.lastIndexOf('.');
if (dotPos == -1) {
From 12a9f9897a4a3c2473933ec7daf336b2044b52da Mon Sep 17 00:00:00 2001
From: Iliya Ivanov
Date: Sun, 7 Dec 2025 17:33:03 +0200
Subject: [PATCH 6/6] WIP
---
.../server/query/SqlTreeAlias.java | 2 +-
.../server/query/SqlTreeBuilder.java | 42 +++++++++++--------
2 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
index 6a13a74e93..fc6459e04e 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java
@@ -92,7 +92,7 @@ private void mapEmbeddedPropertyAlias() {
for (String propJoin : embeddedPropertyJoins) {
String[] split = SplitName.split(propJoin);
// the table alias of the parent path
- String alias = tableAlias(split[0]);
+ String alias = tableAliasManyWhere(split[0]);
aliasMap.put(propJoin, alias);
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
index 7e52df477c..a5a55c4df4 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -362,7 +362,8 @@ private void buildExtraJoins(STreeType desc, List myList) {
// the 'select' part of the query. We may need to add other joins to
// support the predicates or order by clauses.
- // remove ManyWhereJoins from the predicateIncludes
+ // remove ManyWhereJoins from the predicateIncludes and orderByIncludes
+ predicates.orderByIncludes().removeAll(manyWhereJoins.propertyNames());
predicateIncludes.removeAll(manyWhereJoins.propertyNames());
predicateIncludes.addAll(predicates.orderByIncludes());
@@ -649,11 +650,15 @@ private void createExtraJoin(String includeProp) {
* Create a SqlTreeNodeExtraJoin, register and return it.
*/
private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
+ SqlTreeNodeExtraJoin extraJoin = joinRegister.get(propertyName);
+ if (extraJoin != null) {
+ return extraJoin;
+ }
ExtraJoin extra = desc.extraJoin(propertyName);
if (extra == null) {
return null;
} else {
- SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.property(), extra.isContainsMany(), temporalMode);
+ extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.property(), extra.isContainsMany(), temporalMode);
joinRegister.put(propertyName, extraJoin);
return extraJoin;
}
@@ -674,24 +679,25 @@ private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeEx
// no parent possible(parent is root)
return childJoin;
- } else {
- // look in register ...
- String parentPropertyName = includeProp.substring(0, dotPos);
- if (selectIncludes.contains(parentPropertyName)) {
- // parent already handled by select
- return childJoin;
- }
-
- SqlTreeNodeExtraJoin parentJoin = joinRegister.get(parentPropertyName);
- if (parentJoin == null) {
- // we need to create this the parent implicitly...
- parentJoin = createJoinLeaf(parentPropertyName);
- }
-
- parentJoin.addChild(childJoin);
- childJoin = parentJoin;
+ }
+ String parentPropertyName = includeProp.substring(0, dotPos);
+ if (desc.isEmbeddedPath(parentPropertyName)) {
+ // digging in embedded property
+ // so we have to join parent property path if any
includeProp = parentPropertyName;
+ continue;
+ }
+ // look in register ...
+ if (selectIncludes.contains(parentPropertyName)) {
+ // parent already handled by select
+ return childJoin;
}
+
+ SqlTreeNodeExtraJoin parentJoin = createJoinLeaf(parentPropertyName);
+
+ parentJoin.addChild(childJoin);
+ childJoin = parentJoin;
+ includeProp = parentPropertyName;
}
}