diff --git a/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java b/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java index ad5863311..6f048f362 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java +++ b/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java @@ -137,10 +137,10 @@ public class ManyWhereJoins implements Serializable { } /** - * Return true if the findRowCount query just needs the id property in the select clause. + * Return true if the query select includes a formula with join. */ - public boolean isSelectId() { - return !formulaWithJoin; + public boolean isFormulaWithJoin() { + return formulaWithJoin; } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java index fafdb94bc..846c06ffe 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java @@ -123,7 +123,7 @@ public class CQueryBuilder { if (!sqlTree.isIncludeJoins()) { // simple - delete from table ... - return aliasStrip(buildSql("delete", request, predicates, sqlTree).getSql()); + return aliasStrip(buildSql("delete", request, predicates, sqlTree).getSql()); } // wrap as - delete from table where id in (select id ...) String sql = buildSql(null, request, predicates, sqlTree).getSql(); @@ -135,11 +135,11 @@ public class CQueryBuilder { private String buildUpdateSql(OrmQueryRequest request, String rootTableAlias, CQueryPredicates predicates, SqlTree sqlTree) { - String updateClause = "update "+request.getBeanDescriptor().getBaseTable()+" set "+predicates.getDbUpdateClause(); + String updateClause = "update " + request.getBeanDescriptor().getBaseTable() + " set " + predicates.getDbUpdateClause(); if (!sqlTree.isIncludeJoins()) { // simple - update table set ... where ... - return aliasStrip(buildSqlUpdate(updateClause, request, predicates, sqlTree).getSql()); + return aliasStrip(buildSqlUpdate(updateClause, request, predicates, sqlTree).getSql()); } // wrap as - update table set ... where id in (select id ...) String sql = buildSqlUpdate(null, request, predicates, sqlTree).getSql(); @@ -161,7 +161,7 @@ public class CQueryBuilder { * Replace the root table alias. */ private String aliasReplace(String sql, String replaceWith) { - sql = StringHelper.replaceString(sql, "${RTA}.", replaceWith+"."); + sql = StringHelper.replaceString(sql, "${RTA}.", replaceWith + "."); return StringHelper.replaceString(sql, "${RTA}", replaceWith); } @@ -225,20 +225,10 @@ public class CQueryBuilder { ManyWhereJoins manyWhereJoins = query.getManyWhereJoins(); - boolean hasMany = manyWhereJoins.isHasMany(); - if (manyWhereJoins.isSelectId()) { - // just select the id property - query.setSelectId(); - } else { - // select the id and the required formula properties + if (manyWhereJoins.isFormulaWithJoin()) { query.select(manyWhereJoins.getFormulaProperties()); - } - - String sqlSelect = "select count(*)"; - if (hasMany) { - // need to count distinct id's ... - query.setSqlDistinct(true); - sqlSelect = null; + } else { + query.setSelectId(); } CQueryPredicates predicates = new CQueryPredicates(binder, request); @@ -257,6 +247,14 @@ public class CQueryBuilder { sqlTree.addSoftDeletePredicate(query); } + boolean hasMany = sqlTree.hasMany(); + String sqlSelect = "select count(*)"; + if (hasMany) { + // need to count distinct id's ... + query.setSqlDistinct(true); + sqlSelect = null; + } + SqlLimitResponse s = buildSql(sqlSelect, request, predicates, sqlTree); String sql = s.getSql(); if (hasMany || query.isRawSql()) { @@ -488,7 +486,7 @@ public class CQueryBuilder { } if (stripAlias) { // strip the table alias for use in update statement - idSql = StringHelper.replaceString(idSql, "t0.",""); + idSql = StringHelper.replaceString(idSql, "t0.", ""); } sb.append(idSql).append(" "); hasWhere = true; diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java index aaca0a912..6cb2306a0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java @@ -153,4 +153,10 @@ public class SqlTree { return encryptedProps; } + /** + * Return true if the query has a many join. + */ + public boolean hasMany() { + return manyProperty != null || rootNode.hasMany(); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java index 6700f8e16..9aa8ac951 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java @@ -57,4 +57,9 @@ public interface SqlTreeNode { * Load a version of a @History bean with effective dates. */ Version loadVersion(DbReadContext ctx) throws SQLException; + + /** + * Return true if the query has a many join. + */ + boolean hasMany(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java index 60d1e882f..29d7abe14 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -1,11 +1,5 @@ package com.avaje.ebeaninternal.server.query; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.avaje.ebean.Version; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.EntityBean; @@ -24,6 +18,12 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin; import com.avaje.ebeaninternal.server.deploy.id.IdBinder; import com.avaje.ebeaninternal.server.lib.util.StringHelper; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Normal bean included in the query. */ @@ -570,4 +570,14 @@ public class SqlTreeNodeBean implements SqlTreeNode { return true; } + @Override + public boolean hasMany() { + + for (SqlTreeNode child : children) { + if (child.hasMany()) { + return true; + } + } + return false; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java index 97d3a92a4..ae5862267 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java @@ -146,4 +146,9 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode { public Version loadVersion(DbReadContext ctx) throws SQLException { return null; } + + @Override + public boolean hasMany() { + return manyJoin; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java index d3813c7e0..defe4263d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java @@ -1,13 +1,13 @@ package com.avaje.ebeaninternal.server.query; -import java.sql.SQLException; -import java.util.List; - import com.avaje.ebean.bean.EntityBean; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; import com.avaje.ebeaninternal.server.deploy.DbReadContext; import com.avaje.ebeaninternal.server.deploy.DbSqlContext; +import java.sql.SQLException; +import java.util.List; + public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { private final BeanPropertyAssocMany manyProp; @@ -38,4 +38,8 @@ public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { super.appendFrom(ctx, joinType.autoToOuter()); } + @Override + public boolean hasMany() { + return true; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java index eaa0996c0..46c793428 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java @@ -109,4 +109,9 @@ public class SqlTreeNodeManyWhereJoin implements SqlTreeNode { // nothing to do here return null; } + + @Override + public boolean hasMany() { + return true; + } } diff --git a/src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java b/src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java new file mode 100644 index 000000000..f3a448f2a --- /dev/null +++ b/src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java @@ -0,0 +1,35 @@ +package com.avaje.tests.query.other; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.Query; +import com.avaje.tests.model.basic.Order; +import com.avaje.tests.model.basic.ResetBasicData; +import org.avaje.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestQueryRawExpressionMany extends BaseTestCase { + + @Test + public void test() { + + ResetBasicData.reset(); + + Integer quantity = 1; + + Query query = Ebean.find(Order.class) + .where().raw("details.orderQty = ?", quantity) + .query(); + + LoggedSqlCollector.start(); + + query.findRowCount(); + List sql = LoggedSqlCollector.stop(); + + assertThat(sql.get(0)).contains("select count(*) from ( select distinct t0.id c0 from o_order t0 left outer join o_order_detail t1 on t1.order_id = t0.id where t1.order_qty = ?)"); + } +}