diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/DFetchGroup.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/DFetchGroup.java index bc2449d634..08a1e6eb13 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/DFetchGroup.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/DFetchGroup.java @@ -15,8 +15,8 @@ final class DFetchGroup implements SpiFetchGroup { } @Override - public OrmQueryDetail detail() { - return detail.copy(); + public OrmQueryDetail detail(OrmQueryDetail existing) { + return detail.copy(existing); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java index eb15e741e0..c5538b8bc0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java @@ -52,7 +52,7 @@ public Query select(String columns) { @SuppressWarnings("rawtypes") @Override public Query select(FetchGroup fetchGroup) { - this.detail = ((SpiFetchGroup) fetchGroup).detail(); + this.detail = ((SpiFetchGroup) fetchGroup).detail(detail); return this; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index a70c6547ce..2b5f11ea08 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -769,7 +769,7 @@ public SpiQuery copy(SpiEbeanServer server) { copy.useQueryCache = useQueryCache; copy.unmodifiable = unmodifiable; if (detail != null) { - copy.detail = detail.copy(); + copy.detail = detail.copy(null); } copy.temporalMode = temporalMode; copy.firstRow = firstRow; @@ -1387,7 +1387,7 @@ public final Query select(String columns) { @Override public final Query select(FetchGroup fetchGroup) { if (fetchGroup != null) { - this.detail = ((SpiFetchGroup) fetchGroup).detail(); + this.detail = ((SpiFetchGroup) fetchGroup).detail(detail); } return this; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java index d56de43fff..c844b403e5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java @@ -39,12 +39,21 @@ public final class OrmQueryDetail implements Serializable { /** * Return a deep copy of the OrmQueryDetail. */ - public OrmQueryDetail copy() { + public OrmQueryDetail copy(OrmQueryDetail existing) { OrmQueryDetail copy = new OrmQueryDetail(); copy.baseProps = baseProps.copy(); for (Map.Entry entry : fetchPaths.entrySet()) { copy.fetchPaths.put(entry.getKey(), entry.getValue().copy()); } + if (existing != null) { + // transfer any existing filterMany expressions + for (Map.Entry entry : existing.fetchPaths.entrySet()) { + var filterMany = entry.getValue().getFilterMany(); + if (filterMany != null) { + copy.getChunk(entry.getKey(), true).setFilterMany(filterMany); + } + } + } return copy; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/SpiFetchGroup.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/SpiFetchGroup.java index 35f622f036..58acc92b34 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/SpiFetchGroup.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/SpiFetchGroup.java @@ -10,7 +10,7 @@ public interface SpiFetchGroup extends FetchGroup { /** * Return the detail to use for query execution. */ - OrmQueryDetail detail(); + OrmQueryDetail detail(OrmQueryDetail existing); /** * Return the underlying detail for copy purposes. diff --git a/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java b/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java index cc17a43653..fa41918555 100644 --- a/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java @@ -13,6 +13,7 @@ import org.example.domain.query.QContact; import org.example.domain.query.QCustomer; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import javax.sql.DataSource; @@ -391,6 +392,23 @@ void filterManyOr() { assertThat(q.getGeneratedSql()).contains(" from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where (t1.id is null or ((t1.first_name like ? escape'|' or t1.last_name like ? escape'|'))) order by t0.id"); } + @Test + @DisplayName("Retain filterMany expression when select fetchGroup applied after filterMany") + void filterManyBeforeSelectFetchGroup_expect_filterManyExpressionRetained() { + var fetchGroup = QCustomer.forFetchGroup() + .select(name) + .contacts.fetch(QContact.Alias.email) + .buildFetchGroup(); + + var q = new QCustomer() + .contacts.filterMany(c -> c.firstName.startsWith("R")) + .select(fetchGroup) + .query(); + + q.findList(); + assertThat(q.getGeneratedSql()).contains(" t0.id, t0.name, t1.id, t1.email from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where (t1.id is null or (t1.first_name like ? escape'|')) order by t0.id"); + } + @Test public void testIdIn() {