FIX: SubQuery with fetch-path does not work correctly

This commit is contained in:
Roland Praml
2021-07-13 09:09:30 +02:00
parent 4d15535381
commit 7e265f7bde
3 changed files with 74 additions and 3 deletions
@@ -311,7 +311,7 @@ public final class SqlTreeBuilder {
} else {
// do not read Id on child beans (e.g. when used with fetch())
boolean withId = isNotSingleAttribute();
boolean withId = isNotSingleAttribute() && !subQuery;
return new SqlTreeNodeBean(prefix, prop, props, myList, withId, temporalMode, disableLazyLoad);
}
}
@@ -616,7 +616,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
* Limit the number of fetch joins to Many properties, mark as query joins as needed.
*/
private void markQueryJoins() {
detail.markQueryJoins(beanDescriptor, lazyLoadManyPath, isAllowOneManyFetch(), type != Type.ATTRIBUTE);
detail.markQueryJoins(beanDescriptor, lazyLoadManyPath, isAllowOneManyFetch(), type != Type.ATTRIBUTE && type != Type.SUBQUERY);
}
private boolean isAllowOneManyFetch() {
@@ -629,7 +629,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
@Override
public void setDefaultSelectClause() {
if (type != Type.ATTRIBUTE) {
if (type != Type.ATTRIBUTE && type != Type.SUBQUERY) {
detail.setDefaultSelectClause(beanDescriptor);
} else if (!detail.hasSelectClause()) {
// explicit empty select when single attribute query on non-root fetch path
@@ -6,6 +6,8 @@ import io.ebean.Query;
import org.junit.Test;
import org.tests.model.basic.CKeyParent;
import org.tests.model.basic.Order;
import org.tests.model.basic.OrderDetail;
import org.tests.model.basic.OrderShipment;
import org.tests.model.basic.ResetBasicData;
import org.tests.model.basic.Vehicle;
import org.tests.model.basic.VehicleDriver;
@@ -47,6 +49,75 @@ public class TestSubQuery extends BaseTestCase {
DB.find(Order.class).where().isIn("id", sq).findList();
}
/**
* Testcase, that discovered, that DefaultOrmQuery.setDefaultSelectClause is set on subQueries with fetch path.
* Also checks, that SqlTreeBuilder does not read id on Many2One props.
*/
@Test
public void test_IsInWithFetchSubQuery1() {
List<Integer> productIds = new ArrayList<>();
productIds.add(3);
Query<OrderDetail> sq = DB.createQuery(OrderDetail.class).fetch("order", "id").where()
.isIn("product.id", productIds).query();
// execute the subQuery as copy (generatedSQL must be part of original query)
Query<OrderDetail> debugSq = sq.copy();
debugSq.findSingleAttribute();
assertThat(debugSq.getGeneratedSql()).isEqualTo(
"select t1.id from o_order_detail t0 join o_order t1 on t1.id = t0.order_id where t0.product_id in (?)");
Query<Order> query = DB.find(Order.class).select("shipDate").where().isIn("id", sq).query();
query.findSingleAttribute();
assertThat(query.getGeneratedSql())
.isEqualTo("select t0.ship_date from o_order t0 where (t0.id) in (" + debugSq.getGeneratedSql() + ")");
}
/**
* Test checks, that DefaultOrmQuery.markQueryJoins handles subQuery correct.
*/
@Test
public void test_IsInWithFetchSubQuery2() {
Query<OrderDetail> sq = DB.createQuery(OrderDetail.class).fetch("order.customer", "anniversary").where()
.eq("order.customer.name", "Roland")
.query().setDistinct(true);
// execute the subQuery as copy (generatedSQL must be part of original query)
Query<OrderDetail> debugSq = sq.copy();
debugSq.findSingleAttribute();
Query<Order> query = DB.find(Order.class).select("status").where().isIn("shipDate", sq).query();
query.findSingleAttribute();
assertThat(query.getGeneratedSql())
.isEqualTo("select t0.status from o_order t0 where (t0.ship_date) in (" + debugSq.getGeneratedSql() + ")");
}
/**
* Checks, that SqlTreeBuilder does not read id on One2Many props.
*/
@Test
public void test_IsInWithFetchSubQuery3() {
List<Integer> productIds = new ArrayList<>();
productIds.add(3);
Query<OrderDetail> sq = DB.createQuery(OrderDetail.class).fetch("order.shipments", "id").where()
.isIn("product.id", productIds).query();
// execute the subQuery as copy (generatedSQL must be part of original query)
Query<OrderDetail> debugSq = sq.copy();
debugSq.findSingleAttribute();
Query<OrderShipment> query = DB.find(OrderShipment.class).select("shipTime").where().isIn("id", sq).query();
query.findSingleAttribute();
assertThat(query.getGeneratedSql())
.isEqualTo("select t0.ship_time from or_order_ship t0 where (t0.id) in (" + debugSq.getGeneratedSql() + ")");
}
public void testCompositeKey() {
ResetBasicData.reset();