From 56fee2ea9b68804ef4a3b6d703fdd4abfeb1dff2 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 14:57:12 +1200 Subject: [PATCH 01/65] #789 - findCount() ... with where raw(...) expression that includes a "many" produces incorrect SQL --- .../ebeaninternal/api/ManyWhereJoins.java | 6 ++-- .../server/query/CQueryBuilder.java | 34 +++++++++--------- .../ebeaninternal/server/query/SqlTree.java | 6 ++++ .../server/query/SqlTreeNode.java | 5 +++ .../server/query/SqlTreeNodeBean.java | 22 ++++++++---- .../server/query/SqlTreeNodeExtraJoin.java | 5 +++ .../server/query/SqlTreeNodeManyRoot.java | 10 ++++-- .../query/SqlTreeNodeManyWhereJoin.java | 5 +++ .../other/TestQueryRawExpressionMany.java | 35 +++++++++++++++++++ 9 files changed, 98 insertions(+), 30 deletions(-) create mode 100644 src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java 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 = ?)"); + } +} From 5ce8eb60467aa1c2eaf5496834f8ec7c4c0afb34 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 15:02:05 +1200 Subject: [PATCH 02/65] No effective change - remove unused methods --- .../avaje/ebeaninternal/api/ManyWhereJoins.java | 4 ---- .../avaje/ebeaninternal/server/query/SqlTree.java | 15 --------------- 2 files changed, 19 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java b/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java index 6f048f362..0caab1800 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java +++ b/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java @@ -132,10 +132,6 @@ public class ManyWhereJoins implements Serializable { formulaProperties.append(propertyName); } - public boolean isHasMany() { - return formulaWithJoin || !joins.isEmpty(); - } - /** * Return true if the query select includes a formula with join. */ 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 6cb2306a0..8e7a3906e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java @@ -60,21 +60,6 @@ public class SqlTree { this.includeJoins = includeJoins; } - /** - * Construct for RawSql. - */ - public SqlTree(String summary, SqlTreeNode rootNode) { - this.summary = summary; - this.rootNode = rootNode; - this.selectSql = null; - this.fromSql = null; - this.inheritanceWhereSql = null; - this.encryptedProps = null; - this.manyProperty = null; - this.includes = null; - this.includeJoins = false; //not valid for rawSql - } - /** * Return true if the query includes joins (not valid for rawSql). */ From 5bab9eb64819e6b3f214b2af5d6cf64200ead789 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 15:59:54 +1200 Subject: [PATCH 03/65] #790 - DB Migration with multiple platforms (and no maven H2 dependency) gives: java.lang.NoClassDefFoundError: org/h2/api/Trigger --- src/main/java/com/avaje/ebean/dbmigration/DbMigration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java index e04a67737..18fff98cb 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java +++ b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java @@ -202,10 +202,10 @@ public class DbMigration { // use this flag to stop other plugins like full DDL generation if (!online) { DbOffline.setGenerateMigration(); - if (databasePlatform == null || !platforms.isEmpty()) { + if (databasePlatform == null && !platforms.isEmpty()) { // for multiple platform generation set the general platform // to H2 so that it runs offline without DB connection - setPlatform(DbPlatformName.H2); + setPlatform(platforms.get(0).platform); } } setDefaults(); From ed41e58073576fb1c64abdb17104f8cebf46710f Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 16:01:00 +1200 Subject: [PATCH 04/65] Bump pom version to 7.21.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ec2540282..095de4c32 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 7.20.2-SNAPSHOT + 7.21.1-SNAPSHOT jar avaje-ebeanorm From 7c83010df1669225a9d022ce49999bc17df13ea8 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 16:39:23 +1200 Subject: [PATCH 05/65] #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() --- .../java/com/avaje/ebean/EbeanServer.java | 21 +- src/main/java/com/avaje/ebean/Query.java | 213 +++++++----------- .../server/core/DefaultServer.java | 12 +- .../server/querydefn/DefaultOrmQuery.java | 16 +- .../ebeaninternal/api/TDSpiEbeanServer.java | 10 + 5 files changed, 138 insertions(+), 134 deletions(-) diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index 3392334a6..fc82a2fa7 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -739,12 +739,19 @@ public interface EbeanServer { T getReference(Class beanType, Object id); /** - * Return the number of 'top level' or 'root' entities this query should - * return. + * Return the number of 'top level' or 'root' entities this query should return. * * @see Query#findRowCount() * @see com.avaje.ebean.Query#findFutureRowCount() */ + int findCount(Query query, Transaction transaction); + + /** + * Deprecated in favor of findCount() + * + * Return the number of 'top level' or 'root' entities this query should return. + * @deprecated + */ int findRowCount(Query query, Transaction transaction); /** @@ -868,7 +875,15 @@ public interface EbeanServer { * @return a Future object for the row count query * @see com.avaje.ebean.Query#findFutureRowCount() */ - FutureRowCount findFutureRowCount(Query query, Transaction transaction); + FutureRowCount findFutureCount(Query query, Transaction transaction); + + /** + * Deprecated in favor of findFutureCount(). + * + * Execute find row count query in a background thread. + * @deprecated + */ + FutureRowCount findFutureRowCount(Query query, Transaction transaction); /** * Execute find Id's query in a background thread. diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 42bbd424c..f860cd11c 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -13,10 +13,10 @@ import java.util.Set; *

* Example: Create the query using the API. *

- * + *

*

{@code
  *
- * List orderList = 
+ * List orderList =
  *   ebeanServer.find(Order.class)
  *     .fetch("customer")
  *     .fetch("details")
@@ -26,46 +26,41 @@ import java.util.Set;
  *     .orderBy("customer.id, id desc")
  *     .setMaxRows(50)
  *     .findList();
- *   
+ *
  * ...
  * }
- * *

* Example: The same query using the query language *

- * *
{@code
  *
- * String oql = 
+ * String oql =
  *   	"  find  order "
  *   	+" fetch customer "
  *   	+" fetch details "
  *   	+" where customer.name like :custName and orderDate > :minOrderDate "
  *   	+" order by customer.id, id desc "
  *   	+" limit 50 ";
- *   
+ *
  * Query query = ebeanServer.createQuery(Order.class, oql);
  * query.setParameter("custName", "Rob%");
  * query.setParameter("minOrderDate", lastWeek);
- *   
+ *
  * List orderList = query.findList();
  * ...
  * }
- * *

* Example: Using a named query called "with.cust.and.details" *

- * *
{@code
  *
  * Query query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
  * query.setParameter("custName", "Rob%");
  * query.setParameter("minOrderDate", lastWeek);
- *   
+ *
  * List orderList = query.findList();
  * ...
  * }
- * *

AutoTune

*

* Ebean has built in support for "AutoTune". This is a mechanism where a query @@ -82,7 +77,6 @@ import java.util.Set; * to a remote client or where there is some requirement for "Read Consistency" * guarantees. *

- * *

Query Language

*

* Partial Objects @@ -101,7 +95,6 @@ import java.util.Set; * concurrency checking will occur but only include the fetched properties. * Refer to "ALL Properties/Columns" mode of Optimistic Concurrency checking. *

- * *
{@code
  * [ find  {bean type} [ ( * | {fetch properties} ) ] ]
  * [ fetch {associated bean} [ ( * | {fetch properties} ) ] ]
@@ -109,7 +102,6 @@ import java.util.Set;
  * [ order by {order by properties} ]
  * [ limit {max rows} [ offset {first row} ] ]
  * }
- * *

* FIND {bean type} [ ( * | {fetch properties} ) ] *

@@ -163,50 +155,40 @@ import java.util.Set; *

* Find orders fetching all its properties *

- * *
{@code
  * find order
  * }
- * *

* Find orders fetching all its properties *

- * *
{@code
  * find order (*)
  * }
- * *

* Find orders fetching its id, shipDate and status properties. Note that the id * property is always fetched even if it is not included in the list of fetch * properties. *

- * *
{@code
  * find order (shipDate, status)
  * }
- * *

* Find orders with a named bind variable (that will need to be bound via * {@link Query#setParameter(String, Object)}). *

- * *
{@code
  * find order
  * where customer.name like :custLike
  * }
- * *

* Find orders and also fetch the customer with a named bind parameter. This * will fetch and populate both the order and customer objects. *

- * *
{@code
  * find  order
  * fetch customer
  * where customer.id = :custId
  * }
- * *

* Find orders and also fetch the customer, customer shippingAddress, order * details and related product. Note that customer and product objects will be @@ -215,7 +197,6 @@ import java.util.Set; * objects (associated with each order detail) will have their id, sku and name * populated. *

- * *
{@code
  * find  order
  * fetch customer (name)
@@ -223,7 +204,6 @@ import java.util.Set;
  * fetch details
  * fetch details.product (sku, name)
  * }
- * *

Early parsing of the Query

*

* When you get a Query object from a named query, the query statement has @@ -269,9 +249,8 @@ import java.util.Set; * to make it as easy as possible to use your own SQL to populate entity beans. * Refer to {@link RawSql} . *

- * - * @param - * the type of Entity bean this query will fetch. + * + * @param the type of Entity bean this query will fetch. */ public interface Query { @@ -289,7 +268,7 @@ public interface Query { * Perform an 'As of' query using history tables to return the object graph * as of a time in the past. *

- * To perform this query the DB must have underlying history tables. + * To perform this query the DB must have underlying history tables. *

* * @param asOf the date time in the past at which you want to view the data @@ -399,7 +378,6 @@ public interface Query { * You use {@link #fetch(String, String)} to specify specific properties to fetch * on other non-root level paths of the object graph. *

- * *
{@code
    *
    * List customers =
@@ -412,8 +390,7 @@ public interface Query {
    *
    * }
* - * @param fetchProperties - * the properties to fetch for this bean (* = all properties). + * @param fetchProperties the properties to fetch for this bean (* = all properties). */ Query select(String fetchProperties); @@ -428,7 +405,6 @@ public interface Query { * only those properties are fetched and populated resulting in a * "Partial Object" - a bean that only has some of its properties populated. *

- * *
{@code
    *
    * // query orders...
@@ -437,17 +413,15 @@ public interface Query {
    *       // fetch the customer...
    *       // ... getting the customers name and phone number
    *       .fetch("customer", "name, phoneNumber")
-   * 
+   *
    *       // ... also fetch the customers billing address (* = all properties)
    *       .fetch("customer.billingAddress", "*")
    *       .findList();
    * }
- * *

* If columns is null or "*" then all columns/properties for that path are * fetched. *

- * *
{@code
    *
    * // fetch customers (their id, name and status)
@@ -458,19 +432,16 @@ public interface Query {
    *     .findList();
    *
    * }
- * - * @param path - * the path of an associated (1-1,1-M,M-1,M-M) bean. - * @param fetchProperties - * properties of the associated bean that you want to include in the - * fetch (* means all properties, null also means all properties). + * + * @param path the path of an associated (1-1,1-M,M-1,M-M) bean. + * @param fetchProperties properties of the associated bean that you want to include in the + * fetch (* means all properties, null also means all properties). */ Query fetch(String path, String fetchProperties); /** * Additionally specify a FetchConfig to use a separate query or lazy loading * to load this path. - * *
{@code
    *
    * // fetch customers (their id, name and status)
@@ -500,16 +471,13 @@ public interface Query {
    *
    * }
* - * @param path - * the property of an associated (1-1,1-M,M-1,M-M) bean. + * @param path the property of an associated (1-1,1-M,M-1,M-M) bean. */ Query fetch(String path); /** * Additionally specify a JoinConfig to specify a "query join" and or define * the lazy loading query. - * - * *
{@code
    *
    * // fetch customers (their id, name and status)
@@ -536,7 +504,7 @@ public interface Query {
    * 

* This query will execute against the EbeanServer that was used to create it. *

- * + * * @see EbeanServer#findIds(Query, Transaction) */ List findIds(); @@ -564,7 +532,6 @@ public interface Query { * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use * with Java8 closures. *

- * *
{@code
    *
    *  ebeanServer.find(Customer.class)
@@ -578,8 +545,7 @@ public interface Query {
    *
    * }
* - * @param consumer - * the consumer used to process the queried beans. + * @param consumer the consumer used to process the queried beans. */ void findEach(QueryEachConsumer consumer); @@ -591,8 +557,6 @@ public interface Query { * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use * with Java8 closures. *

- - * *
{@code
    *
    *  ebeanServer.find(Customer.class)
@@ -611,8 +575,7 @@ public interface Query {
    *
    * }
* - * @param consumer - * the consumer used to process the queried beans. + * @param consumer the consumer used to process the queried beans. */ void findEachWhile(QueryEachWhileConsumer consumer); @@ -621,7 +584,6 @@ public interface Query { *

* This query will execute against the EbeanServer that was used to create it. *

- * *
{@code
    *
    * List customers =
@@ -640,7 +602,6 @@ public interface Query {
    * 

* This query will execute against the EbeanServer that was used to create it. *

- * *
{@code
    *
    * Set customers =
@@ -663,7 +624,6 @@ public interface Query {
    * You can use setMapKey() so specify the property values to be used as keys
    * on the map. If one is not specified then the id property is used.
    * 

- * *
{@code
    *
    * Map map =
@@ -672,7 +632,7 @@ public interface Query {
    *     .findMap();
    *
    * }
- * + * * @see EbeanServer#findMap(Query, Transaction) */ Map findMap(); @@ -693,7 +653,6 @@ public interface Query { * This is useful when your predicates dictate that your query should only * return 0 or 1 results. *

- * *
{@code
    *
    * // assuming the sku of products is unique...
@@ -703,16 +662,14 @@ public interface Query {
    *         .findUnique();
    * ...
    * }
- * *

* It is also useful with finding objects by their id when you want to specify * further join information. *

- * *
{@code
    *
    * // Fetch order 1 and additionally fetch join its order details...
-   * Order order = 
+   * Order order =
    *     ebeanServer.find(Order.class)
    *       .setId(1)
    *       .fetch("details")
@@ -731,13 +688,13 @@ public interface Query {
   /**
    * Return versions of a @History entity bean.
    * 

- * Note that this query will work against view based history implementations - * but not sql2011 standards based implementations that require a start and - * end timestamp to be specified. + * Note that this query will work against view based history implementations + * but not sql2011 standards based implementations that require a start and + * end timestamp to be specified. *

*

- * Generally this query is expected to be a find by id or unique predicates query. - * It will execute the query against the history returning the versions of the bean. + * Generally this query is expected to be a find by id or unique predicates query. + * It will execute the query against the history returning the versions of the bean. *

*/ List> findVersions(); @@ -745,8 +702,8 @@ public interface Query { /** * Return versions of a @History entity bean between the 2 timestamps. *

- * Generally this query is expected to be a find by id or unique predicates query. - * It will execute the query against the history returning the versions of the bean. + * Generally this query is expected to be a find by id or unique predicates query. + * It will execute the query against the history returning the versions of the bean. *

*/ List> findVersionsBetween(Timestamp start, Timestamp end); @@ -774,6 +731,14 @@ public interface Query { * This is the number of 'top level' or 'root level' entities. *

*/ + int findCount(); + + /** + * Deprecated in favor of findCount(). + *

+ * Return the count of entities this query should return. + * @deprecated + */ int findRowCount(); /** @@ -783,9 +748,24 @@ public interface Query { * execution status (isDone etc) and get the value (with or without a * timeout). *

- * + * * @return a Future object for the row count query */ + FutureRowCount findFutureCount(); + + /** + * Deprecated in favor of findFutureCount(). + *

+ * Execute find row count query in a background thread. + *

+ * This returns a Future object which can be used to cancel, check the + * execution status (isDone etc) and get the value (with or without a + * timeout). + *

+ * + * @return a Future object for the row count query + * @deprecated + */ FutureRowCount findFutureRowCount(); /** @@ -795,7 +775,7 @@ public interface Query { * execution status (isDone etc) and get the value (with or without a * timeout). *

- * + * * @return a Future object for the list of Id's */ FutureIds findFutureIds(); @@ -821,7 +801,6 @@ public interface Query { * If maxRows is not set on the query prior to calling findPagedList() then a * PersistenceException is thrown. *

- * *
{@code
    *
    *  PagedList pagedList = Ebean.find(Order.class)
@@ -843,24 +822,21 @@ public interface Query {
 
   /**
    * Set a named bind parameter. Named parameters have a colon to prefix the name.
-   * 
    * 
{@code
    *
    * // a query with a named parameter
    * String oql = "find order where status = :orderStatus";
-   * 
+   *
    * Query query = ebeanServer.find(Order.class, oql);
-   * 
+   *
    * // bind the named parameter
    * query.bind("orderStatus", OrderStatus.NEW);
    * List list = query.findList();
    *
    * }
- * - * @param name - * the parameter name - * @param value - * the parameter value + * + * @param name the parameter name + * @param value the parameter value */ Query setParameter(String name, Object value); @@ -868,25 +844,22 @@ public interface Query { * Set an ordered bind parameter according to its position. Note that the * position starts at 1 to be consistent with JDBC PreparedStatement. You need * to set a parameter value for each ? you have in the query. - * *
{@code
    *
    * // a query with a positioned parameter
    * String oql = "where status = ? order by id desc";
-   * 
+   *
    * Query query = ebeanServer.createQuery(Order.class, oql);
-   * 
+   *
    * // bind the parameter
    * query.setParameter(1, OrderStatus.NEW);
-   * 
+   *
    * List list = query.findList();
    *
    * }
- * - * @param position - * the parameter bind position starting from 1 (not 0) - * @param value - * the parameter bind value. + * + * @param position the parameter bind position starting from 1 (not 0) + * @param value the parameter bind value. */ Query setParameter(int position, Object value); @@ -896,7 +869,6 @@ public interface Query { * You can use this to have further control over the query. For example adding * fetch joins. *

- * *
{@code
    *
    * Order order =
@@ -919,10 +891,9 @@ public interface Query {
 
   /**
    * Add a single Expression to the where clause returning the query.
-   * 
    * 
{@code
    *
-   * List newOrders = 
+   * List newOrders =
    *     ebeanServer.find(Order.class)
    * 		.where().eq("status", Order.NEW)
    * 		.findList();
@@ -936,7 +907,6 @@ public interface Query {
    * Add Expressions to the where clause with the ability to chain on the
    * ExpressionList. You can use this for adding multiple expressions to the
    * where clause.
-   * 
    * 
{@code
    *
    * List orders =
@@ -947,9 +917,9 @@ public interface Query {
    *     .findList();
    *
    * }
- * - * @see Expr + * * @return The ExpressionList for adding expressions to. + * @see Expr */ ExpressionList where(); @@ -984,9 +954,8 @@ public interface Query { * each customer you only want to get the new orders they placed since last * week. In this case you can use filterMany() to filter the orders. *

- * *
{@code
-   * 
+   *
    * List list =
    *     ebeanServer.find(Customer.class)
    *     // .fetch("orders", new FetchConfig().lazy())
@@ -995,20 +964,17 @@ public interface Query {
    *     .where().ilike("name", "rob%")
    *     .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
    *     .findList();
-   * 
+   *
    * }
- * *

* Please note you have to be careful that you add expressions to the correct * expression list - as there is one for the 'root level' and one for each * filterMany that you have. *

- * - * @param propertyName - * the name of the many property that you want to have a filter on. - * + * + * @param propertyName the name of the many property that you want to have a filter on. * @return the expression list that you add filter expressions for the many - * to. + * to. */ ExpressionList filterMany(String propertyName); @@ -1021,9 +987,9 @@ public interface Query { * Note that this returns the ExpressionList (so you can add multiple * expressions to the query in a fluent API way). *

- * - * @see Expr + * * @return The ExpressionList for adding more expressions to. + * @see Expr */ ExpressionList having(); @@ -1037,9 +1003,8 @@ public interface Query { * than the ExpressionList. This is useful when you want to further specify * something on the query. *

- * - * @param addExpressionToHaving - * the expression to add to the having clause. + * + * @param addExpressionToHaving the expression to add to the having clause. * @return the Query object */ Query having(Expression addExpressionToHaving); @@ -1151,9 +1116,8 @@ public interface Query { /** * Set the maximum number of rows to return in the query. - * - * @param maxRows - * the maximum number of rows to return in the query. + * + * @param maxRows the maximum number of rows to return in the query. */ Query setMaxRows(int maxRows); @@ -1162,11 +1126,10 @@ public interface Query { *

* If no property is set then the id property is used. *

- * *
{@code
    *
    * // Assuming sku is unique for products...
-   *    
+   *
    * Map productMap =
    *     ebeanServer.find(Product.class)
    *     // use sku for keys...
@@ -1174,9 +1137,8 @@ public interface Query {
    *     .findMap();
    *
    * }
- * - * @param mapKey - * the property to use as keys for a map. + * + * @param mapKey the property to use as keys for a map. */ Query setMapKey(String mapKey); @@ -1203,7 +1165,7 @@ public interface Query { /** * Set to true if this query should execute against the doc store. *

- * When setting this you may also consider disabling lazy loading. + * When setting this you may also consider disabling lazy loading. *

*/ Query setUseDocStore(boolean useDocStore); @@ -1226,9 +1188,8 @@ public interface Query { * preparedStatement. If the timeout occurs an exception will be thrown - this * will be a SQLException wrapped up in a PersistenceException. *

- * - * @param secs - * the query timeout limit in seconds. Zero means there is no limit. + * + * @param secs the query timeout limit in seconds. Zero means there is no limit. */ Query setTimeout(int secs); @@ -1260,7 +1221,7 @@ public interface Query { * Return true if this query has forUpdate set. */ boolean isForUpdate(); - + /** * Set root table alias. */ @@ -1274,7 +1235,7 @@ public interface Query { /** * Set true if you want to disable lazy loading. *

- * That is, once the object graph is returned further lazy loading is disabled. + * That is, once the object graph is returned further lazy loading is disabled. *

*/ Query setDisableLazyLoading(boolean disableLazyLoading); diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index 5bc59014d..75f91947e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -1152,12 +1152,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } - public int findRowCount(Query query, Transaction t) { + public int findCount(Query query, Transaction t) { SpiQuery copy = ((SpiQuery) query).copy(); return findRowCountWithCopy(copy, t); } + public int findRowCount(Query query, Transaction t) { + return findCount(query, t); + } + public int findRowCountWithCopy(Query query, Transaction t) { SpiOrmQueryRequest request = createQueryRequest(Type.ROWCOUNT, query, t); @@ -1213,7 +1217,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } - public FutureRowCount findFutureRowCount(Query q, Transaction t) { + public FutureRowCount findFutureCount(Query q, Transaction t) { SpiQuery copy = ((SpiQuery) q).copy(); copy.setFutureFetch(true); @@ -1228,6 +1232,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return queryFuture; } + public FutureRowCount findFutureRowCount(Query q, Transaction t) { + return findFutureCount(q, t); + } + public FutureIds findFutureIds(Query query, Transaction t) { SpiQuery copy = ((SpiQuery) query).copy(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index befb221ce..073e9215d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1048,11 +1048,16 @@ public class DefaultOrmQuery implements SpiQuery { } @Override - public int findRowCount() { + public int findCount() { // a copy of this query is made in the server // as the query needs to modified (so we modify // the copy rather than this query instance) - return server.findRowCount(this, null); + return server.findCount(this, null); + } + + @Override + public int findRowCount() { + return findCount(); } @Override @@ -1119,9 +1124,14 @@ public class DefaultOrmQuery implements SpiQuery { return server.findFutureList(this, null); } + @Override + public FutureRowCount findFutureCount() { + return server.findFutureCount(this, null); + } + @Override public FutureRowCount findFutureRowCount() { - return server.findFutureRowCount(this, null); + return findFutureCount(); } @Override diff --git a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java index 97c93f13f..345a4472f 100644 --- a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java @@ -455,6 +455,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return null; } + @Override + public int findCount(Query query, Transaction transaction) { + return 0; + } + @Override public int findRowCount(Query query, Transaction transaction) { return 0; @@ -480,6 +485,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return null; } + @Override + public FutureRowCount findFutureCount(Query query, Transaction transaction) { + return null; + } + @Override public FutureRowCount findFutureRowCount(Query query, Transaction transaction) { return null; From dc7c8544320ac4f1d9fd2462ff0489e37d4ff09b Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 19:06:21 +1200 Subject: [PATCH 06/65] #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() --- .../java/com/avaje/ebean/EbeanServer.java | 4 +-- .../java/com/avaje/ebean/ExpressionList.java | 14 +++++++++ src/main/java/com/avaje/ebean/Model.java | 25 +++++++++++++--- src/main/java/com/avaje/ebean/PagedList.java | 21 +++++++++++++ .../expression/DefaultExpressionList.java | 14 +++++++-- .../expression/FilterExpressionList.java | 14 +++++++-- .../server/expression/JunctionExpression.java | 14 +++++++-- .../server/query/LimitOffsetPagedList.java | 30 +++++++++++++------ .../lib/sql/TestDataSourceMaxWithEntity.java | 2 +- .../TestFutureRowCountErrorHandling.java | 2 +- .../com/avaje/tests/basic/MainDbBoolean.java | 2 +- .../tests/draftable/LinkQueryPublishTest.java | 2 +- .../tests/m2m/TestM2MDeleteWithCascade.java | 4 +-- .../tests/model/basic/ResetBasicData.java | 6 ++-- .../tests/model/noid/TestInsertNoIdBean.java | 2 +- .../model/selfref/TestTextJsonSelfRef.java | 2 +- .../tests/query/TestQueryFindFutureList.java | 4 +-- .../tests/query/TestQueryFindPagedList.java | 20 ++++++------- .../query/TestQueryPlanCacheRowCount.java | 4 +-- .../com/avaje/tests/query/TestRowCount.java | 2 +- .../joins/TestDisjunctWhereOuterOnMany.java | 2 +- .../query/other/TestFormulaWithFindCount.java | 2 +- .../TestObjectGraphNodeStatsCollection.java | 2 +- .../other/TestQueryConversationRowCount.java | 2 +- .../other/TestQueryRawExpressionMany.java | 2 +- .../other/TestQueryRowCountWithMany.java | 4 +-- .../tests/query/other/TestSelfParent.java | 2 +- .../softdelete/TestSoftDeletePagingList.java | 2 +- .../tests/query/sqlquery/SqlQueryTests.java | 2 +- .../tests/rawsql/TestOrderReportTotal.java | 2 +- .../tests/rawsql/TestRawSqlOrmQuery.java | 12 ++++---- .../tests/softdelete/TestSoftDeleteBasic.java | 8 ++--- .../TestExplicitTransactionMode.java | 2 +- .../transaction/TestNestedBeginRequired.java | 6 ++-- .../TestNestedBeginRequiredWithFailure.java | 6 ++-- .../TestNestedBeginRequiresNew.java | 6 ++-- ...TestNestedBeginRequiresNewWithFailure.java | 6 ++-- 37 files changed, 175 insertions(+), 81 deletions(-) diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index fc82a2fa7..93f1af715 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -741,8 +741,8 @@ public interface EbeanServer { /** * Return the number of 'top level' or 'root' entities this query should return. * - * @see Query#findRowCount() - * @see com.avaje.ebean.Query#findFutureRowCount() + * @see Query#findCount() + * @see Query#findFutureCount() */ int findCount(Query query, Transaction transaction); diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index 34f4c441a..cd7cf962d 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -182,6 +182,13 @@ public interface ExpressionList { * This is the number of 'top level' or 'root level' entities. *

*/ + int findCount(); + + /** + * Deprecated in favor of findCount(). + * + * @deprecated + */ int findRowCount(); /** @@ -228,6 +235,13 @@ public interface ExpressionList { * * @return a Future object for the row count query */ + FutureRowCount findFutureCount(); + + /** + * Deprecated in favor of findFutureCount(). + * + * @deprecated + */ FutureRowCount findFutureRowCount(); /** diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java index ab87eb41d..edf0572e1 100644 --- a/src/main/java/com/avaje/ebean/Model.java +++ b/src/main/java/com/avaje/ebean/Model.java @@ -677,19 +677,36 @@ public abstract class Model { /** * Executes a find row count query in a background thread. *

- * Equivalent to {@link Query#findFutureRowCount()} + * Equivalent to {@link Query#findFutureCount()} + */ + public FutureRowCount findFutureCount() { + return query().findFutureCount(); + } + + /** + * Deprecated in favor of findFutureCount(). + *

+ * Equivalent to {@link Query#findFutureCount()} */ public FutureRowCount findFutureRowCount() { - return query().findFutureRowCount(); + return query().findFutureCount(); } /** * Returns the total number of entities for this type. * *

- * Equivalent to {@link Query#findRowCount()} + * Equivalent to {@link Query#findCount()} + */ + public int findCount() { + return query().findCount(); + } + + /** + * Deprecated in favor of findCount(). + * @deprecated */ public int findRowCount() { - return query().findRowCount(); + return query().findCount(); } /** diff --git a/src/main/java/com/avaje/ebean/PagedList.java b/src/main/java/com/avaje/ebean/PagedList.java index 22347967d..9efb6a830 100644 --- a/src/main/java/com/avaje/ebean/PagedList.java +++ b/src/main/java/com/avaje/ebean/PagedList.java @@ -110,6 +110,13 @@ public interface PagedList { * wrapped in the unchecked PersistenceException (which might be preferrable). *

*/ + void loadCount(); + + /** + * Deprecated in favor of loadCount(). + * + * @deprecated + */ void loadRowCount(); /** @@ -138,6 +145,13 @@ public interface PagedList { * * }
*/ + Future getFutureCount(); + + /** + * Deprecated in favor of getFutureCount(). + * + * @deprecated + */ Future getFutureRowCount(); /** @@ -170,6 +184,13 @@ public interface PagedList { * * }
*/ + int getTotalCount(); + + /** + * Deprecated in favor of getTotalCount(). + * + * @deprecated + */ int getTotalRowCount(); /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index a6cd1001d..1d84c4029 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -323,9 +323,14 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findFutureIds(); } + @Override + public FutureRowCount findFutureCount() { + return query.findFutureCount(); + } + @Override public FutureRowCount findFutureRowCount() { - return query.findFutureRowCount(); + return findFutureCount(); } @Override @@ -338,9 +343,14 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findPagedList(); } + @Override + public int findCount() { + return query.findCount(); + } + @Override public int findRowCount() { - return query.findRowCount(); + return findCount(); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java index 91ffc2406..18284b842 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java @@ -48,9 +48,14 @@ public class FilterExpressionList extends DefaultExpressionList { return rootQuery.findFutureList(); } + @Override + public FutureRowCount findFutureCount() { + return rootQuery.findFutureCount(); + } + @Override public FutureRowCount findFutureRowCount() { - return rootQuery.findFutureRowCount(); + return findFutureCount(); } @Override @@ -63,9 +68,14 @@ public class FilterExpressionList extends DefaultExpressionList { return rootQuery.findMap(); } + @Override + public int findCount() { + return rootQuery.findCount(); + } + @Override public int findRowCount() { - return rootQuery.findRowCount(); + return findCount(); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 6b49e2492..e6bb77918 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -360,9 +360,14 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.findFutureList(); } + @Override + public FutureRowCount findFutureCount() { + return exprList.findFutureCount(); + } + @Override public FutureRowCount findFutureRowCount() { - return exprList.findFutureRowCount(); + return findFutureCount(); } @Override @@ -401,10 +406,15 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression } @Override - public int findRowCount() { + public int findCount() { return exprList.findRowCount(); } + @Override + public int findRowCount() { + return findCount(); + } + @Override public Set findSet() { return exprList.findSet(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/LimitOffsetPagedList.java b/src/main/java/com/avaje/ebeaninternal/server/query/LimitOffsetPagedList.java index 9906ac223..eb5ef408c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/LimitOffsetPagedList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/LimitOffsetPagedList.java @@ -43,19 +43,27 @@ public class LimitOffsetPagedList implements PagedList { this.firstRow = query.getFirstRow(); } - public void loadRowCount() { - getFutureRowCount(); + public void loadCount() { + getFutureCount(); } - public Future getFutureRowCount() { + public void loadRowCount() { + loadCount(); + } + + public Future getFutureCount() { synchronized (monitor) { if (futureRowCount == null) { - futureRowCount = server.findFutureRowCount(query, null); + futureRowCount = server.findFutureCount(query, null); } return futureRowCount; } } + public Future getFutureRowCount() { + return getFutureCount(); + } + public List getList() { synchronized (monitor) { if (list == null) { @@ -67,7 +75,7 @@ public class LimitOffsetPagedList implements PagedList { public int getTotalPageCount() { - int rowCount = getTotalRowCount(); + int rowCount = getTotalCount(); if (rowCount == 0) { return 0; } else { @@ -75,7 +83,7 @@ public class LimitOffsetPagedList implements PagedList { } } - public int getTotalRowCount() { + public int getTotalCount() { synchronized (monitor) { if (futureRowCount != null) { try { @@ -89,13 +97,17 @@ public class LimitOffsetPagedList implements PagedList { if (foregroundTotalRowCount > -1) return foregroundTotalRowCount; // just using foreground thread - foregroundTotalRowCount = server.findRowCount(query, null); + foregroundTotalRowCount = server.findCount(query, null); return foregroundTotalRowCount; } } + public int getTotalRowCount() { + return getTotalCount(); + } + public boolean hasNext() { - return (firstRow + maxRows) < getTotalRowCount(); + return (firstRow + maxRows) < getTotalCount(); } public boolean hasPrev() { @@ -110,7 +122,7 @@ public class LimitOffsetPagedList implements PagedList { int first = firstRow + 1; int last = firstRow + getList().size(); - int total = getTotalRowCount(); + int total = getTotalCount(); return first + to + last + of + total; } diff --git a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestDataSourceMaxWithEntity.java b/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestDataSourceMaxWithEntity.java index 8abda7611..ad97b3b5e 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestDataSourceMaxWithEntity.java +++ b/src/test/java/com/avaje/ebeaninternal/server/lib/sql/TestDataSourceMaxWithEntity.java @@ -54,7 +54,7 @@ public class TestDataSourceMaxWithEntity extends BaseTestCase { public void run() { - server.find(Customer.class).findRowCount(); + server.find(Customer.class).findCount(); try { System.out.println(position+" sleep " + sleepMillis); Thread.sleep(sleepMillis); diff --git a/src/test/java/com/avaje/ebeaninternal/server/query/TestFutureRowCountErrorHandling.java b/src/test/java/com/avaje/ebeaninternal/server/query/TestFutureRowCountErrorHandling.java index 278466bec..233bd873b 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/query/TestFutureRowCountErrorHandling.java +++ b/src/test/java/com/avaje/ebeaninternal/server/query/TestFutureRowCountErrorHandling.java @@ -29,7 +29,7 @@ public class TestFutureRowCountErrorHandling extends BaseTestCase { .where().eq("doesNotExist", "this will fail") .query(); - FutureRowCount futureRowCount = server.findFutureRowCount(query, null); + FutureRowCount futureRowCount = server.findFutureCount(query, null); QueryFutureRowCount internalRowCount = (QueryFutureRowCount)futureRowCount; Transaction t = internalRowCount.getTransaction(); diff --git a/src/test/java/com/avaje/tests/basic/MainDbBoolean.java b/src/test/java/com/avaje/tests/basic/MainDbBoolean.java index a4929a481..e3c2ab758 100644 --- a/src/test/java/com/avaje/tests/basic/MainDbBoolean.java +++ b/src/test/java/com/avaje/tests/basic/MainDbBoolean.java @@ -147,7 +147,7 @@ public class MainDbBoolean { .setAutoTune(false) .order("id"); - int rc = query.findRowCount(); + int rc = query.findCount(); Assert.assertTrue(rc > 0); diff --git a/src/test/java/com/avaje/tests/draftable/LinkQueryPublishTest.java b/src/test/java/com/avaje/tests/draftable/LinkQueryPublishTest.java index 03d885b35..762068b91 100644 --- a/src/test/java/com/avaje/tests/draftable/LinkQueryPublishTest.java +++ b/src/test/java/com/avaje/tests/draftable/LinkQueryPublishTest.java @@ -39,7 +39,7 @@ public class LinkQueryPublishTest { .setMaxRows(10) .findPagedList(); - assertThat(pagedList.getTotalRowCount()).isEqualTo(3); + assertThat(pagedList.getTotalCount()).isEqualTo(3); assertThat(pagedList.getList()).hasSize(3); diff --git a/src/test/java/com/avaje/tests/m2m/TestM2MDeleteWithCascade.java b/src/test/java/com/avaje/tests/m2m/TestM2MDeleteWithCascade.java index ca13a9710..6525886ba 100644 --- a/src/test/java/com/avaje/tests/m2m/TestM2MDeleteWithCascade.java +++ b/src/test/java/com/avaje/tests/m2m/TestM2MDeleteWithCascade.java @@ -39,13 +39,13 @@ public class TestM2MDeleteWithCascade extends BaseTestCase { List roleIds = new ArrayList(); Collections.addAll(roleIds, r0.getRoleid(), r1.getRoleid()); - int rc = Ebean.find(MRole.class).where().idIn(roleIds).findRowCount(); + int rc = Ebean.find(MRole.class).where().idIn(roleIds).findCount(); Assert.assertEquals("roles not deleted", 2, rc); Ebean.deleteAll(roles); - rc = Ebean.find(MRole.class).where().idIn(roleIds).findRowCount(); + rc = Ebean.find(MRole.class).where().idIn(roleIds).findCount(); Assert.assertEquals("roles deleted now", 0, rc); } diff --git a/src/test/java/com/avaje/tests/model/basic/ResetBasicData.java b/src/test/java/com/avaje/tests/model/basic/ResetBasicData.java index db13c5fee..b4d3bd35d 100644 --- a/src/test/java/com/avaje/tests/model/basic/ResetBasicData.java +++ b/src/test/java/com/avaje/tests/model/basic/ResetBasicData.java @@ -25,7 +25,7 @@ public class ResetBasicData { server.execute(new TxRunnable() { public void run() { - if (server.find(Product.class).findRowCount() > 0) { + if (server.find(Product.class).findCount() > 0) { // we can't really delete this base data as // the test rely on the products being in there return; @@ -72,7 +72,7 @@ public class ResetBasicData { public void insertCountries() { - if (server.find(Country.class).findRowCount() > 0) { + if (server.find(Country.class).findCount() > 0) { return; } @@ -94,7 +94,7 @@ public class ResetBasicData { public void insertProducts() { - if (server.find(Product.class).findRowCount() > 0) { + if (server.find(Product.class).findCount() > 0) { return; } server.execute(new TxRunnable() { diff --git a/src/test/java/com/avaje/tests/model/noid/TestInsertNoIdBean.java b/src/test/java/com/avaje/tests/model/noid/TestInsertNoIdBean.java index 18ff9e86d..af954a29e 100644 --- a/src/test/java/com/avaje/tests/model/noid/TestInsertNoIdBean.java +++ b/src/test/java/com/avaje/tests/model/noid/TestInsertNoIdBean.java @@ -18,7 +18,7 @@ public class TestInsertNoIdBean extends BaseTestCase { Ebean.save(bean); - int rowCount = Ebean.find(NoIdBean.class).findRowCount(); + int rowCount = Ebean.find(NoIdBean.class).findCount(); assertTrue("rowCount:"+rowCount, rowCount > 0); diff --git a/src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.java b/src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.java index 2e33211b7..4c928bbf7 100644 --- a/src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.java +++ b/src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.java @@ -18,7 +18,7 @@ public class TestTextJsonSelfRef extends BaseTestCase { Ebean.execute(new TxRunnable() { public void run() { - if (Ebean.find(SelfRefCustomer.class).findRowCount() == 0) { + if (Ebean.find(SelfRefCustomer.class).findCount() == 0) { SelfRefCustomer c1 = new SelfRefCustomer(); c1.setName("Foo"); c1.setReferredBy(c1); diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindFutureList.java b/src/test/java/com/avaje/tests/query/TestQueryFindFutureList.java index 51d92f922..b540a731b 100644 --- a/src/test/java/com/avaje/tests/query/TestQueryFindFutureList.java +++ b/src/test/java/com/avaje/tests/query/TestQueryFindFutureList.java @@ -48,7 +48,7 @@ public class TestQueryFindFutureList extends BaseTestCase { // wait for it to complete List orders = futureList.getUnchecked(); - assertEquals(Ebean.find(Order.class).findRowCount(), orders.size()); + assertEquals(Ebean.find(Order.class).findCount(), orders.size()); } @Test @@ -61,7 +61,7 @@ public class TestQueryFindFutureList extends BaseTestCase { // wait for it to complete List orders = futureList.getUnchecked(1, TimeUnit.SECONDS); - assertEquals(Ebean.find(Order.class).findRowCount(), orders.size()); + assertEquals(Ebean.find(Order.class).findCount(), orders.size()); } } diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java b/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java index 501136f8c..3581fb475 100644 --- a/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java +++ b/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java @@ -83,7 +83,7 @@ public class TestQueryFindPagedList extends BaseTestCase { pagedList.loadRowCount(); List orders = pagedList.getList(); - int totalRowCount = pagedList.getTotalRowCount(); + int totalRowCount = pagedList.getTotalCount(); assertThat(orders.size()).isLessThan(totalRowCount); assertTrue(pagedList.hasNext()); @@ -96,9 +96,9 @@ public class TestQueryFindPagedList extends BaseTestCase { .setMaxRows(3) .findPagedList(); - pagedList2.loadRowCount(); + pagedList2.loadCount(); List orders2 = pagedList2.getList(); - int totalRowCount2 = pagedList2.getTotalRowCount(); + int totalRowCount2 = pagedList2.getTotalCount(); assertTrue(pagedList2.hasNext()); assertTrue(pagedList2.hasPrev()); @@ -161,11 +161,11 @@ public class TestQueryFindPagedList extends BaseTestCase { PagedList pagedList = Ebean.find(Order.class).setMaxRows(3).findPagedList(); - Future rowCount = pagedList.getFutureRowCount(); + Future rowCount = pagedList.getFutureCount(); List orders = pagedList.getList(); // these are each getting the total row count - int totalRowCount = pagedList.getTotalRowCount(); + int totalRowCount = pagedList.getTotalCount(); Integer totalRowCountWithTimeout = rowCount.get(30, TimeUnit.SECONDS); Integer totalRowCountViaFuture = rowCount.get(); @@ -183,9 +183,9 @@ public class TestQueryFindPagedList extends BaseTestCase { // fetch less that total orders (page size 3) PagedList pagedList = Ebean.find(Order.class).setMaxRows(3).findPagedList(); - pagedList.loadRowCount(); + pagedList.loadCount(); List orders = pagedList.getList(); - int totalRowCount = pagedList.getTotalRowCount(); + int totalRowCount = pagedList.getTotalCount(); assertThat(orders.size()).isLessThan(totalRowCount); } @@ -207,10 +207,10 @@ public class TestQueryFindPagedList extends BaseTestCase { try { List orders = pagedList.getList(); - int totalRowCount = pagedList.getTotalRowCount(); + int totalRowCount = pagedList.getTotalCount(); // invoke it again but cached... - int totalRowCountAgain = pagedList.getTotalRowCount(); + int totalRowCountAgain = pagedList.getTotalCount(); List loggedSql = LoggedSqlCollector.stop(); @@ -242,7 +242,7 @@ public class TestQueryFindPagedList extends BaseTestCase { LoggedSqlCollector.start(); - pagedList.getTotalRowCount(); + pagedList.getTotalCount(); pagedList.getList(); List loggedSql = LoggedSqlCollector.stop(); diff --git a/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java b/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java index 1ee498639..b31f33fe5 100644 --- a/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java +++ b/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java @@ -29,7 +29,7 @@ public class TestQueryPlanCacheRowCount extends BaseTestCase { List list0 = query.findList(); Assert.assertEquals(rc0, list0.size()); - int rc1 = query.findRowCount(); + int rc1 = query.findCount(); Assert.assertEquals(rc0, rc1); List ids1 = query.findIds(); @@ -48,7 +48,7 @@ public class TestQueryPlanCacheRowCount extends BaseTestCase { Query query2 = Ebean.find(Order.class).where().eq("status", Order.Status.NEW) .ge("id", idGt).order().desc("id"); - int rc2 = query2.findRowCount(); + int rc2 = query2.findCount(); System.out.println("Expection Not same " + rc0 + " != " + rc2); Assert.assertNotSame(rc0, rc2); diff --git a/src/test/java/com/avaje/tests/query/TestRowCount.java b/src/test/java/com/avaje/tests/query/TestRowCount.java index b8b47c3b0..ae7196f04 100644 --- a/src/test/java/com/avaje/tests/query/TestRowCount.java +++ b/src/test/java/com/avaje/tests/query/TestRowCount.java @@ -21,7 +21,7 @@ public class TestRowCount extends BaseTestCase { Query query = Ebean.find(Order.class).fetch("details").where().gt("id", 1) .gt("details.id", 1).order("id desc"); - int rc = query.findRowCount(); + int rc = query.findCount(); List ids = query.findIds(); diff --git a/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterOnMany.java b/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterOnMany.java index 5f41d95cc..3b9f2dab4 100644 --- a/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterOnMany.java +++ b/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterOnMany.java @@ -44,7 +44,7 @@ public class TestDisjunctWhereOuterOnMany extends BaseTestCase { .query(); List list = query.findList(); - int rowCount = query.findRowCount(); + int rowCount = query.findCount(); // select distinct t0.id c0, t0.name c1 // from uuone t0 diff --git a/src/test/java/com/avaje/tests/query/other/TestFormulaWithFindCount.java b/src/test/java/com/avaje/tests/query/other/TestFormulaWithFindCount.java index 105028ee7..f4cc122ef 100644 --- a/src/test/java/com/avaje/tests/query/other/TestFormulaWithFindCount.java +++ b/src/test/java/com/avaje/tests/query/other/TestFormulaWithFindCount.java @@ -31,7 +31,7 @@ public class TestFormulaWithFindCount extends BaseTestCase { } ExpressionList expressionList = server.find(Order.class).where().gt("totalAmount", 1d); - int rowCount = expressionList.findRowCount(); + int rowCount = expressionList.findCount(); Assert.assertEquals(list.size(), rowCount); } diff --git a/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java b/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java index c9efc59f5..744559b44 100644 --- a/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java +++ b/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java @@ -28,7 +28,7 @@ public class TestObjectGraphNodeStatsCollection extends BaseTestCase { MetaInfoManager infoManager = server.getMetaInfoManager(); - server.find(Order.class).findRowCount(); + server.find(Order.class).findCount(); infoManager.collectNodeStatistics(true); infoManager.collectQueryPlanStatistics(true); diff --git a/src/test/java/com/avaje/tests/query/other/TestQueryConversationRowCount.java b/src/test/java/com/avaje/tests/query/other/TestQueryConversationRowCount.java index f76397580..01d64fc36 100644 --- a/src/test/java/com/avaje/tests/query/other/TestQueryConversationRowCount.java +++ b/src/test/java/com/avaje/tests/query/other/TestQueryConversationRowCount.java @@ -47,7 +47,7 @@ public class TestQueryConversationRowCount extends BaseTestCase { LoggedSqlCollector.start(); - query.findRowCount(); + query.findCount(); // select count(*) from ( // select distinct t0.id c0 diff --git a/src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java b/src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java index f3a448f2a..f21ea9212 100644 --- a/src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java +++ b/src/test/java/com/avaje/tests/query/other/TestQueryRawExpressionMany.java @@ -27,7 +27,7 @@ public class TestQueryRawExpressionMany extends BaseTestCase { LoggedSqlCollector.start(); - query.findRowCount(); + query.findCount(); 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 = ?)"); diff --git a/src/test/java/com/avaje/tests/query/other/TestQueryRowCountWithMany.java b/src/test/java/com/avaje/tests/query/other/TestQueryRowCountWithMany.java index 240039bea..bf472df71 100644 --- a/src/test/java/com/avaje/tests/query/other/TestQueryRowCountWithMany.java +++ b/src/test/java/com/avaje/tests/query/other/TestQueryRowCountWithMany.java @@ -47,7 +47,7 @@ public class TestQueryRowCountWithMany extends BaseTestCase { Assert.assertTrue(generatedSql.contains(" order by t0.cretime")); - int rowCount = query.findRowCount(); + int rowCount = query.findCount(); // select count(*) from o_order t0 // left outer join o_order_detail t1 on t1.order_id = t0.id @@ -84,7 +84,7 @@ public class TestQueryRowCountWithMany extends BaseTestCase { .orderBy("cretime asc"); LoggedSqlCollector.start(); - query.findRowCount(); + query.findCount(); List sqlLogged = LoggedSqlCollector.stop(); diff --git a/src/test/java/com/avaje/tests/query/other/TestSelfParent.java b/src/test/java/com/avaje/tests/query/other/TestSelfParent.java index 9d42bf022..7e8e35306 100644 --- a/src/test/java/com/avaje/tests/query/other/TestSelfParent.java +++ b/src/test/java/com/avaje/tests/query/other/TestSelfParent.java @@ -14,7 +14,7 @@ public class TestSelfParent extends BaseTestCase { @Test public void test() { - if (Ebean.find(SelfParent.class).findRowCount() > 0) { + if (Ebean.find(SelfParent.class).findCount() > 0) { // only run once return; } diff --git a/src/test/java/com/avaje/tests/query/softdelete/TestSoftDeletePagingList.java b/src/test/java/com/avaje/tests/query/softdelete/TestSoftDeletePagingList.java index 430facf91..caa3312da 100644 --- a/src/test/java/com/avaje/tests/query/softdelete/TestSoftDeletePagingList.java +++ b/src/test/java/com/avaje/tests/query/softdelete/TestSoftDeletePagingList.java @@ -31,7 +31,7 @@ public class TestSoftDeletePagingList { .setMaxRows(10) .findPagedList(); - int totalRowCount = pagedList.getTotalRowCount(); + int totalRowCount = pagedList.getTotalCount(); List resultList = pagedList.getList(); List sql = LoggedSqlCollector.stop(); diff --git a/src/test/java/com/avaje/tests/query/sqlquery/SqlQueryTests.java b/src/test/java/com/avaje/tests/query/sqlquery/SqlQueryTests.java index c5e507287..4e7cefb0c 100644 --- a/src/test/java/com/avaje/tests/query/sqlquery/SqlQueryTests.java +++ b/src/test/java/com/avaje/tests/query/sqlquery/SqlQueryTests.java @@ -111,7 +111,7 @@ public class SqlQueryTests extends BaseTestCase { ResetBasicData.reset(); - int expectedRows = Ebean.find(Order.class).findRowCount(); + int expectedRows = Ebean.find(Order.class).findCount(); final AtomicInteger count = new AtomicInteger(); diff --git a/src/test/java/com/avaje/tests/rawsql/TestOrderReportTotal.java b/src/test/java/com/avaje/tests/rawsql/TestOrderReportTotal.java index 5f7b53bef..d114541df 100644 --- a/src/test/java/com/avaje/tests/rawsql/TestOrderReportTotal.java +++ b/src/test/java/com/avaje/tests/rawsql/TestOrderReportTotal.java @@ -56,7 +56,7 @@ public class TestOrderReportTotal extends BaseTestCase { .where() .gt("order.id", 2) .istartsWith("order.customer.name","rob") - .findRowCount(); + .findCount(); assertThat(detailsCount).isGreaterThan(0); } diff --git a/src/test/java/com/avaje/tests/rawsql/TestRawSqlOrmQuery.java b/src/test/java/com/avaje/tests/rawsql/TestRawSqlOrmQuery.java index 3ae69818f..c8424ac7f 100644 --- a/src/test/java/com/avaje/tests/rawsql/TestRawSqlOrmQuery.java +++ b/src/test/java/com/avaje/tests/rawsql/TestRawSqlOrmQuery.java @@ -78,14 +78,14 @@ public class TestRawSqlOrmQuery extends BaseTestCase { Query query = Ebean.find(Customer.class); query.setRawSql(rawSql); - int initialRowCount = query.findRowCount(); + int initialRowCount = query.findCount(); query.setFirstRow(1); query.setMaxRows(2); List list = query.findList(); - int rowCount = query.findRowCount(); - FutureRowCount futureRowCount = query.findFutureRowCount(); + int rowCount = query.findCount(); + FutureRowCount futureRowCount = query.findFutureCount(); Assert.assertEquals(initialRowCount, rowCount); Assert.assertEquals(initialRowCount, futureRowCount.get().intValue()); @@ -110,12 +110,12 @@ public class TestRawSqlOrmQuery extends BaseTestCase { Query query = Ebean.find(Customer.class); query.setRawSql(rawSql); - int initialRowCount = query.findRowCount(); + int initialRowCount = query.findCount(); PagedList page = query.setMaxRows(2).findPagedList(); List list = page.getList(); - int rowCount = page.getTotalRowCount(); + int rowCount = page.getTotalCount(); Assert.assertEquals(2, list.size()); Assert.assertEquals(initialRowCount, rowCount); @@ -186,7 +186,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase { query.order("id desc"); PagedList pagedList = query.findPagedList(); pagedList.getList(); - pagedList.getTotalRowCount(); + pagedList.getTotalCount(); assertThat(query.getGeneratedSql()).contains("order by o.id desc limit 100"); } diff --git a/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java b/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java index 30b01c627..91ac41dda 100644 --- a/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java +++ b/src/test/java/com/avaje/tests/softdelete/TestSoftDeleteBasic.java @@ -71,7 +71,7 @@ public class TestSoftDeleteBasic extends BaseTestCase { bean.setName("two"); Ebean.save(bean); - int rowCountBefore = Ebean.find(EBasicSoftDelete.class).findRowCount(); + int rowCountBefore = Ebean.find(EBasicSoftDelete.class).findCount(); Ebean.delete(EBasicSoftDelete.class, bean.getId()); @@ -79,7 +79,7 @@ public class TestSoftDeleteBasic extends BaseTestCase { // -- test .findRowCount() LoggedSqlCollector.start(); - int rowCountAfter = Ebean.find(EBasicSoftDelete.class).findRowCount(); + int rowCountAfter = Ebean.find(EBasicSoftDelete.class).findCount(); List loggedSql = LoggedSqlCollector.stop(); assertThat(loggedSql).hasSize(1); @@ -91,7 +91,7 @@ public class TestSoftDeleteBasic extends BaseTestCase { // -- test includeSoftDeletes().findRowCount() LoggedSqlCollector.start(); - int rowCountFull = Ebean.find(EBasicSoftDelete.class).setIncludeSoftDeletes().findRowCount(); + int rowCountFull = Ebean.find(EBasicSoftDelete.class).setIncludeSoftDeletes().findCount(); assertThat(rowCountFull).isGreaterThan(rowCountAfter); loggedSql = LoggedSqlCollector.stop(); @@ -197,7 +197,7 @@ public class TestSoftDeleteBasic extends BaseTestCase { Ebean.find(EBasicSoftDelete.class) .setId(bean.getId()) .where() - .includeSoftDeletes() + .setIncludeSoftDeletes() .findUnique(); assertThat(fetchAllWithLazy.getChildren()).hasSize(3); diff --git a/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java b/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java index b33455217..f1edf9e53 100644 --- a/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java +++ b/src/test/java/com/avaje/tests/transaction/TestExplicitTransactionMode.java @@ -70,7 +70,7 @@ public class TestExplicitTransactionMode extends BaseTestCase { } // rollback as expected - assertEquals(0, ebeanServer.find(UTMaster.class).findRowCount()); + assertEquals(0, ebeanServer.find(UTMaster.class).findCount()); UTMaster bean1 = new UTMaster("one1"); UTMaster bean2 = new UTMaster("two2"); diff --git a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequired.java b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequired.java index 7782712f7..163463ed5 100644 --- a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequired.java +++ b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequired.java @@ -25,11 +25,11 @@ public class TestNestedBeginRequired extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.required()); try { - server.find(Country.class).findRowCount(); + server.find(Country.class).findCount(); someInnerMethod(); - server.find(Product.class).findRowCount(); + server.find(Product.class).findCount(); txn.commit(); @@ -45,7 +45,7 @@ public class TestNestedBeginRequired extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.required()); try { - server.find(Customer.class).findRowCount(); + server.find(Customer.class).findCount(); txn.commit(); diff --git a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiredWithFailure.java b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiredWithFailure.java index 7b3945ed8..1f52a9c03 100644 --- a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiredWithFailure.java +++ b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiredWithFailure.java @@ -23,12 +23,12 @@ public class TestNestedBeginRequiredWithFailure extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.required()); try { - server.find(Country.class).findRowCount(); + server.find(Country.class).findCount(); try { someInnerMethodWithFailure(); - server.find(Product.class).findRowCount(); + server.find(Product.class).findCount(); txn.commit(); } catch (RuntimeException e) { @@ -50,7 +50,7 @@ public class TestNestedBeginRequiredWithFailure extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.required()); try { - server.find(Customer.class).findRowCount(); + server.find(Customer.class).findCount(); EBasic basic = new EBasic(); basic.setName("ignore"); diff --git a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNew.java b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNew.java index 11a231d09..21d85d4b0 100644 --- a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNew.java +++ b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNew.java @@ -25,11 +25,11 @@ public class TestNestedBeginRequiresNew extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.requiresNew()); try { - server.find(Country.class).findRowCount(); + server.find(Country.class).findCount(); someInnerMethod(); - server.find(Product.class).findRowCount(); + server.find(Product.class).findCount(); txn.commit(); @@ -45,7 +45,7 @@ public class TestNestedBeginRequiresNew extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.requiresNew()); try { - server.find(Customer.class).findRowCount(); + server.find(Customer.class).findCount(); txn.commit(); } finally { diff --git a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNewWithFailure.java b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNewWithFailure.java index eea7e3175..a99324c69 100644 --- a/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNewWithFailure.java +++ b/src/test/java/com/avaje/tests/transaction/TestNestedBeginRequiresNewWithFailure.java @@ -25,14 +25,14 @@ public class TestNestedBeginRequiresNewWithFailure extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.requiresNew()); try { - server.find(Country.class).findRowCount(); + server.find(Country.class).findCount(); try { someInnerMethodWithFailure(); } catch (RuntimeException e) { logger.info("Inner method failed with " + e.getMessage()); } - server.find(Product.class).findRowCount(); + server.find(Product.class).findCount(); txn.commit(); @@ -48,7 +48,7 @@ public class TestNestedBeginRequiresNewWithFailure extends BaseTestCase { Transaction txn = server.beginTransaction(TxScope.requiresNew()); try { - server.find(Customer.class).findRowCount(); + server.find(Customer.class).findCount(); if (server != null) { throw new RuntimeException("barf"); From d82148248ce7d2c982150134ec18c4c0ba77e1e4 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 20:55:34 +1200 Subject: [PATCH 07/65] No effective change - javadoc tidy --- .../server/transaction/DefaultTransactionThreadLocal.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultTransactionThreadLocal.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultTransactionThreadLocal.java index b6834ec41..2b255d106 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultTransactionThreadLocal.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultTransactionThreadLocal.java @@ -4,8 +4,7 @@ import com.avaje.ebeaninternal.api.SpiTransaction; import com.avaje.ebeaninternal.server.transaction.TransactionMap.State; /** - * Used by EbeanMgr to store its Transactions in a ThreadLocal. This way the - * transaction objects don't have to passed around. + * Used to store Transactions in a ThreadLocal. */ public final class DefaultTransactionThreadLocal { @@ -99,7 +98,7 @@ public final class DefaultTransactionThreadLocal { * block. *

*

-   * Ebean.beingTransaction();
+   * Ebean.beginTransaction();
    * try {
    *   // ... perform some actions in a single transaction
    *
@@ -110,8 +109,6 @@ public final class DefaultTransactionThreadLocal {
    *   Ebean.endTransaction();
    * }
    * 
- *

- *

*/ public static void end(String serverName) { From b4a1d520679ed834e74b1fbe815a6a7e3d7ff658 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 21:24:31 +1200 Subject: [PATCH 08/65] #791 - ENH: Add transaction.setRollbackOnly() ... (and Ebean.setRollbackOnly()) --- src/main/java/com/avaje/ebean/Ebean.java | 7 +++ .../java/com/avaje/ebean/Transaction.java | 5 ++ .../avaje/ebeaninternal/api/ScopeTrans.java | 9 ++++ .../ebeaninternal/api/ScopedTransaction.java | 5 ++ .../server/transaction/JdbcTransaction.java | 14 +++++ .../TestTransactionRollbackOnly.java | 53 +++++++++++++++++++ 6 files changed, 93 insertions(+) create mode 100644 src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java diff --git a/src/main/java/com/avaje/ebean/Ebean.java b/src/main/java/com/avaje/ebean/Ebean.java index 924c1c221..ffd330b1a 100644 --- a/src/main/java/com/avaje/ebean/Ebean.java +++ b/src/main/java/com/avaje/ebean/Ebean.java @@ -499,6 +499,13 @@ public final class Ebean { serverMgr.getDefaultServer().endTransaction(); } + /** + * Mark the current transaction as rollback only. + */ + public static void setRollbackOnly() { + serverMgr.getDefaultServer().currentTransaction().setRollbackOnly(); + } + /** * Return a map of the differences between two objects of the same type. *

diff --git a/src/main/java/com/avaje/ebean/Transaction.java b/src/main/java/com/avaje/ebean/Transaction.java index cd2db3004..526fe28bb 100644 --- a/src/main/java/com/avaje/ebean/Transaction.java +++ b/src/main/java/com/avaje/ebean/Transaction.java @@ -74,6 +74,11 @@ public interface Transaction extends Closeable { */ void rollback(Throwable e) throws PersistenceException; + /** + * Mark the transaction for rollback only. + */ + void setRollbackOnly(); + /** * If the transaction is active then perform rollback. Otherwise do nothing. */ diff --git a/src/main/java/com/avaje/ebeaninternal/api/ScopeTrans.java b/src/main/java/com/avaje/ebeaninternal/api/ScopeTrans.java index ecdda3085..c2eda8690 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/ScopeTrans.java +++ b/src/main/java/com/avaje/ebeaninternal/api/ScopeTrans.java @@ -181,6 +181,15 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler { return e; } + /** + * Mark the underlying transaction as rollback only. + */ + public void setRollbackOnly() { + if (transaction != null) { + transaction.setRollbackOnly(); + } + } + /** * An Exception was caught and may or may not cause a rollback to occur. * Returns the exception and this should be thrown by the calling code. diff --git a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java index a8a98d5c2..44f7eb62c 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java @@ -49,6 +49,11 @@ public class ScopedTransaction implements SpiTransaction { scopeTrans.rollback(e); } + @Override + public void setRollbackOnly() { + scopeTrans.setRollbackOnly(); + } + @Override public void end() throws PersistenceException { try { diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java index 9edd8b395..79fe82379 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java @@ -66,6 +66,8 @@ public class JdbcTransaction implements SpiTransaction { */ protected boolean active; + protected boolean rollbackOnly; + /** * The underlying Connection. */ @@ -903,6 +905,10 @@ public class JdbcTransaction implements SpiTransaction { */ @Override public void commit() throws RollbackException { + if (rollbackOnly) { + rollback(); + return; + } if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } @@ -945,6 +951,14 @@ public class JdbcTransaction implements SpiTransaction { } } + /** + * Mark the transaction as rollback only. + */ + @Override + public void setRollbackOnly() { + this.rollbackOnly = true; + } + /** * Rollback the transaction. */ diff --git a/src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java b/src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java new file mode 100644 index 000000000..5b536718c --- /dev/null +++ b/src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java @@ -0,0 +1,53 @@ +package com.avaje.tests.transaction; + +import com.avaje.ebean.Ebean; +import com.avaje.ebean.Transaction; +import com.avaje.ebean.annotation.Transactional; +import com.avaje.tests.model.basic.EBasic; +import org.junit.Test; + +import static org.assertj.core.api.StrictAssertions.assertThat; + +public class TestTransactionRollbackOnly { + + private EBasic one; + + private EBasic two; + + @Test + public void transaction_setRollbackOnly() { + + doVia_currentTransaction(); + + assertThat(one.getId()).isNotNull(); + assertThat(Ebean.find(EBasic.class, one.getId())).isNull(); + } + + @Transactional + protected void doVia_currentTransaction() { + + one = new EBasic("WillNotSave"); + Ebean.save(one); + + Transaction transaction = Ebean.currentTransaction(); + transaction.setRollbackOnly(); + } + + @Test + public void test_Ebean_setRollbackOnly() { + + do_Ebean_setRollbackOnly(); + + assertThat(two.getId()).isNotNull(); + assertThat(Ebean.find(EBasic.class, two.getId())).isNull(); + } + + @Transactional + protected void do_Ebean_setRollbackOnly() { + + two = new EBasic("WillNotSave"); + Ebean.save(two); + + Ebean.setRollbackOnly(); + } +} From 0f0028eb1f6c4885dbc6cbf593804f5fc21d4dde Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 21:27:58 +1200 Subject: [PATCH 09/65] [maven-release-plugin] prepare release avaje-ebeanorm-7.21.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 095de4c32..56e582df9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 7.21.1-SNAPSHOT + 7.21.1 jar avaje-ebeanorm @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - HEAD + avaje-ebeanorm-7.21.1 From 74c6c71301be4788e246ceabd4486d4e0bfb4bdb Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 21:28:17 +1200 Subject: [PATCH 10/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 56e582df9..2bc032908 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 7.21.1 + 7.21.2-SNAPSHOT jar avaje-ebeanorm @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - avaje-ebeanorm-7.21.1 + HEAD From 4d1340c16cb6542f581a5bdc400bd76e10281529 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 22:46:07 +1200 Subject: [PATCH 11/65] No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name --- .../com/avaje/ebeaninternal/api/SpiQuery.java | 10 ++++++++-- .../server/deploy/BeanPropertyAssocMany.java | 2 +- .../server/query/SqlTreeBuilder.java | 2 +- .../server/querydefn/DefaultOrmQuery.java | 15 +++++++-------- .../server/querydefn/OrmQueryPlanKey.java | 8 ++++---- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java index 8b4ebffa0..6ca8ca878 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java @@ -593,9 +593,15 @@ public interface SpiQuery extends Query { */ OrmQueryDetail getDetail(); - TableJoin getIncludeTableJoin(); + /** + * Return the extra join for a M2M lazy load. + */ + TableJoin getM2mIncludeJoin(); - void setIncludeTableJoin(TableJoin includeTableJoin); + /** + * Set the extra join for a M2M lazy load. + */ + void setM2MIncludeJoin(TableJoin includeTableJoin); /** * Return the property used to specify keys for a map. diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 4581ea350..a64586646 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -357,7 +357,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { String tableAlias = manyToMany ? "int_." : "t0."; if (manyToMany) { - query.setIncludeTableJoin(inverseJoin); + query.setM2MIncludeJoin(inverseJoin); } String rawWhere = deriveWhereParentIdSql(true, tableAlias); String expr = descriptor.getParentIdInExpr(parentIds.size(), rawWhere); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java index 2621b50b2..aef2012fb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java @@ -106,7 +106,7 @@ public class SqlTreeBuilder { this.query = request.getQuery(); this.disableLazyLoad = query.isDisableLazyLoading(); this.subQuery = Type.SUBQUERY.equals(query.getType()) || Type.ID_LIST.equals(query.getType()); - this.includeJoin = query.getIncludeTableJoin(); + this.includeJoin = query.getM2mIncludeJoin(); this.manyWhereJoins = query.getManyWhereJoins(); this.queryDetail = query.getDetail(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 073e9215d..dedc9f597 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -55,7 +55,7 @@ public class DefaultOrmQuery implements SpiQuery { * For lazy loading of ManyToMany we need to add a join to the intersection table. This is that * join to the intersection table. */ - private TableJoin includeTableJoin; + private TableJoin m2mIncludeJoin; private ProfilingListener profilingListener; @@ -571,7 +571,7 @@ public class DefaultOrmQuery implements SpiQuery { public DefaultOrmQuery copy(EbeanServer server) { DefaultOrmQuery copy = new DefaultOrmQuery(beanDescriptor, server, expressionFactory); - copy.includeTableJoin = includeTableJoin; + copy.m2mIncludeJoin = m2mIncludeJoin; copy.profilingListener = profilingListener; // copy.query = query; @@ -846,7 +846,7 @@ public class DefaultOrmQuery implements SpiQuery { */ CQueryPlanKey createQueryPlanKey() { - queryPlanKey = new OrmQueryPlanKey(includeTableJoin, type, detail, maxRows, firstRow, + queryPlanKey = new OrmQueryPlanKey(m2mIncludeJoin, type, detail, maxRows, firstRow, disableLazyLoading, orderBy, distinct, sqlDistinct, mapKey, id, bindParams, whereExpressions, havingExpressions, temporalMode, forUpdate, rootTableAlias, rawSql, updateProperties); @@ -1264,14 +1264,13 @@ public class DefaultOrmQuery implements SpiQuery { return "Query [" + whereExpressions + "]"; } - @Override - public TableJoin getIncludeTableJoin() { - return includeTableJoin; + public TableJoin getM2mIncludeJoin() { + return m2mIncludeJoin; } @Override - public void setIncludeTableJoin(TableJoin includeTableJoin) { - this.includeTableJoin = includeTableJoin; + public void setM2MIncludeJoin(TableJoin m2mIncludeJoin) { + this.m2mIncludeJoin = m2mIncludeJoin; } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java index 6023754b1..11b1c6616 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java @@ -14,7 +14,7 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin; */ public class OrmQueryPlanKey implements CQueryPlanKey { - private final TableJoin includeTableJoin; + private final String m2mIncludeTable; private final String orderByAsSting; private final OrmQueryDetail detail; private final SpiExpression where; @@ -38,7 +38,7 @@ public class OrmQueryPlanKey implements CQueryPlanKey { public OrmQueryPlanKey(TableJoin includeTableJoin, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) { - this.includeTableJoin = includeTableJoin; + this.m2mIncludeTable = includeTableJoin == null ? null : includeTableJoin.getTable(); this.type = type; this.detail = detail; this.maxRows = maxRows; @@ -69,7 +69,7 @@ public class OrmQueryPlanKey implements CQueryPlanKey { builder.add(hasIdValue); builder.add(temporalMode); builder.add(rawSqlKey == null ? 0 : rawSqlKey.hashCode()); - builder.add(includeTableJoin != null ? includeTableJoin.queryHash() : 0); + builder.add(m2mIncludeTable); builder.add(rootTableAlias); if (detail != null) { @@ -120,7 +120,7 @@ public class OrmQueryPlanKey implements CQueryPlanKey { if (hasIdValue != that.hasIdValue) return false; if (type != that.type) return false; if (temporalMode != that.temporalMode) return false; - if (includeTableJoin != null ? !includeTableJoin.equals(that.includeTableJoin) : that.includeTableJoin != null) return false; + if (m2mIncludeTable != null ? !m2mIncludeTable.equals(that.m2mIncludeTable) : that.m2mIncludeTable != null) return false; if (orderByAsSting != null ? !orderByAsSting.equals(that.orderByAsSting) : that.orderByAsSting != null) return false; if (where != null ? !where.isSameByPlan(that.where) : that.where != null) return false; if (having != null ? !having.isSameByPlan(that.having) : that.having != null) return false; From 4a9f8cef0e7c5316f9b2a9aa73f12d40ddbcf45e Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 22:49:10 +1200 Subject: [PATCH 12/65] No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name --- .../server/querydefn/OrmQueryPlanKeyTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java index f9f4fdb3e..7af9dfd88 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java @@ -30,7 +30,7 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_diffTableJoinNull() { - TableJoin tableJoin = tableJoin("id", "customer_id"); + TableJoin tableJoin = tableJoin("table", "id", "customer_id"); OrmQueryPlanKey key1 = new OrmQueryPlanKey(tableJoin, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null, null); OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null, null); @@ -41,8 +41,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_diffTableJoin() { - TableJoin tableJoin1 = tableJoin("id", "customer_id"); - TableJoin tableJoin2 = tableJoin("id", "other_customer_id"); + TableJoin tableJoin1 = tableJoin("one", "id", "customer_id"); + TableJoin tableJoin2 = tableJoin("two", "id", "customer_id"); OrmQueryPlanKey key1 = new OrmQueryPlanKey(tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null, null); OrmQueryPlanKey key2 = new OrmQueryPlanKey(tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null, null); @@ -53,8 +53,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_sameTableJoin() { - TableJoin tableJoin1 = tableJoin("id", "customer_id"); - TableJoin tableJoin2 = tableJoin("id", "customer_id"); + TableJoin tableJoin1 = tableJoin("one", "id", "customer_id"); + TableJoin tableJoin2 = tableJoin("one", "id", "customer_id"); OrmQueryPlanKey key1 = new OrmQueryPlanKey(tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null, null); OrmQueryPlanKey key2 = new OrmQueryPlanKey(tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, false, null, null, null); @@ -63,9 +63,9 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { } @NotNull - private TableJoin tableJoin(String col1, String col2) { + private TableJoin tableJoin(String table, String col1, String col2) { DeployTableJoin deploy = new DeployTableJoin(); - deploy.setTable("myTable"); + deploy.setTable(table); deploy.addJoinColumn(new DeployTableJoinColumn(col1, col2)); return new TableJoin(deploy); } From 77deab5cf06ffc2630183cfadfa745b42673f4a1 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 22:52:48 +1200 Subject: [PATCH 13/65] #792 - Change Logging Rollback message on org.avaje.ebean.TXN from INFO level to DEBUG level --- .../ebeaninternal/server/transaction/TransactionManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java index 954dc4b75..47abc01b5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java @@ -344,12 +344,12 @@ public class TransactionManager { public void notifyOfRollback(SpiTransaction transaction, Throwable cause) { try { - if (TXN_LOGGER.isInfoEnabled()) { + if (TXN_LOGGER.isDebugEnabled()) { String msg = transaction.getLogPrefix() + "Rollback"; if (cause != null) { msg += " error: " + formatThrowable(cause); } - TXN_LOGGER.info(msg); + TXN_LOGGER.debug(msg); } for (TransactionEventListener listener : transactionEventListeners) { From 76b33511e1e3f1b96ff84dd5e2223e035454f12d Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:14:08 +1200 Subject: [PATCH 14/65] #793 - com.avaje.ebean.event.changelog.BeanChange not keeping passed id value --- src/main/java/com/avaje/ebean/event/changelog/BeanChange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/avaje/ebean/event/changelog/BeanChange.java b/src/main/java/com/avaje/ebean/event/changelog/BeanChange.java index 225e04010..4deb57d00 100644 --- a/src/main/java/com/avaje/ebean/event/changelog/BeanChange.java +++ b/src/main/java/com/avaje/ebean/event/changelog/BeanChange.java @@ -80,7 +80,7 @@ public class BeanChange { * Set the bean id (for JSON tools). */ public void setId(Object id) { - this.id = this.id; + this.id = id; } /** From e621900de98ed147d95512e27b842b000083cb30 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:23:43 +1200 Subject: [PATCH 15/65] #794 - Refactor - tidy code, remove unused method arguments --- .../java/com/avaje/ebean/dbmigration/model/MTable.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java index 8e8610751..e7e8c66f6 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java @@ -270,17 +270,15 @@ public class MTable { } // compare existing columns (look for dropped columns) - int columnPosition = 0; for (MColumn existingColumn : allColumns()) { MColumn newColumn = newColumnMap.get(existingColumn.getName()); if (newColumn == null) { - diffDropColumn(modelDiff, existingColumn, columnPosition, newTable); + diffDropColumn(modelDiff, existingColumn); } else if (newColumn.isDraftOnly() && !draft) { // effectively a drop column (draft only column on a non-draft table) logger.trace("... drop column {} from table {} as now draftOnly", newColumn.getName(), name); - diffDropColumn(modelDiff, existingColumn, columnPosition, newTable); + diffDropColumn(modelDiff, existingColumn); } - columnPosition++; } if (addColumn != null) { @@ -540,7 +538,7 @@ public class MTable { /** * Add a 'drop column' to the diff. */ - private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn, int columnPosition, MTable newTable) { + private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn) { DropColumn dropColumn = new DropColumn(); dropColumn.setTableName(name); From abbdda810ae2d3e9d56b87df6270500135a0f4fc Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:23:57 +1200 Subject: [PATCH 16/65] #794 - Refactor - tidy code, remove unused method arguments --- .../avaje/ebeaninternal/server/type/DefaultTypeManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java index 9ced06aaf..9b4ad0f40 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java @@ -209,7 +209,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { initialiseJacksonTypes(config); if (bootupClasses != null) { - initialiseCustomScalarTypes(jsonDateTime, bootupClasses, config); + initialiseCustomScalarTypes(jsonDateTime, bootupClasses); initialiseScalarConverters(bootupClasses); initialiseCompoundTypes(bootupClasses); } @@ -682,7 +682,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { * interface and register it with this TypeManager. *

*/ - protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses, ServerConfig serverConfig) { + protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses) { ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(mode); From 87c479cd950f694deac40a62220c5af431d7589f Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:24:30 +1200 Subject: [PATCH 17/65] #794 - Refactor - tidy code, remove unused imports --- src/main/java/com/avaje/ebean/SqlQuery.java | 2 -- .../config/dbplatform/DatabasePlatform.java | 1 - .../avaje/ebean/event/BeanPersistAdapter.java | 2 -- .../ebean/event/BeanPersistController.java | 2 -- .../server/cache/CachedManyIds.java | 1 - .../server/cache/DefaultServerCache.java | 1 - .../server/deploy/AssocOneHelp.java | 1 - .../server/deploy/AssocOneHelpRefInherit.java | 1 - .../deploy/BeanPropertyAssocManyJsonHelp.java | 1 - .../server/el/ElMatchBuilder.java | 2 -- .../server/grammer/antlr/EQLLexer.java | 15 ++++++++----- .../server/grammer/antlr/EQLParser.java | 22 ++++++++++++++----- .../server/persist/ExeOrmUpdate.java | 1 - .../server/persist/ExeUpdateSql.java | 1 - .../persist/dmlbind/BindableRequest.java | 5 ++--- .../DefaultPersistenceContext.java | 1 - .../docstore/api/support/DocStructure.java | 3 +-- 17 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/avaje/ebean/SqlQuery.java b/src/main/java/com/avaje/ebean/SqlQuery.java index 9541f7e69..58e4b721d 100644 --- a/src/main/java/com/avaje/ebean/SqlQuery.java +++ b/src/main/java/com/avaje/ebean/SqlQuery.java @@ -2,8 +2,6 @@ package com.avaje.ebean; import java.io.Serializable; import java.util.List; -import java.util.Map; -import java.util.Set; /** * Query object for performing native SQL queries that return SqlRow's. diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java index edf934518..952e71b51 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java @@ -15,7 +15,6 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; -import java.util.Properties; /** * Database platform specific settings. diff --git a/src/main/java/com/avaje/ebean/event/BeanPersistAdapter.java b/src/main/java/com/avaje/ebean/event/BeanPersistAdapter.java index 44b814e92..7cdab42ba 100644 --- a/src/main/java/com/avaje/ebean/event/BeanPersistAdapter.java +++ b/src/main/java/com/avaje/ebean/event/BeanPersistAdapter.java @@ -1,7 +1,5 @@ package com.avaje.ebean.event; -import java.util.Set; - import com.avaje.ebean.config.ServerConfig; /** diff --git a/src/main/java/com/avaje/ebean/event/BeanPersistController.java b/src/main/java/com/avaje/ebean/event/BeanPersistController.java index d10fe07e3..84a53a79a 100644 --- a/src/main/java/com/avaje/ebean/event/BeanPersistController.java +++ b/src/main/java/com/avaje/ebean/event/BeanPersistController.java @@ -1,7 +1,5 @@ package com.avaje.ebean.event; -import java.util.Set; - /** * Used to enhance or override the default bean persistence mechanism. *

diff --git a/src/main/java/com/avaje/ebeaninternal/server/cache/CachedManyIds.java b/src/main/java/com/avaje/ebeaninternal/server/cache/CachedManyIds.java index 069057a6f..b84c91194 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/cache/CachedManyIds.java +++ b/src/main/java/com/avaje/ebeaninternal/server/cache/CachedManyIds.java @@ -4,7 +4,6 @@ import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java index d7db64a10..f6444b840 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java +++ b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java @@ -1,7 +1,6 @@ package com.avaje.ebeaninternal.server.cache; import com.avaje.ebean.BackgroundExecutor; -import com.avaje.ebean.EbeanServer; import com.avaje.ebean.cache.ServerCache; import com.avaje.ebean.cache.ServerCacheOptions; import com.avaje.ebean.cache.ServerCacheStatistics; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelp.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelp.java index 93dd8210c..4fe99bdb9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelp.java @@ -1,7 +1,6 @@ package com.avaje.ebeaninternal.server.deploy; import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebean.bean.EntityBeanIntercept; import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebeaninternal.server.query.SqlJoinType; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java index ffb37a85d..4791cb641 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java @@ -1,7 +1,6 @@ package com.avaje.ebeaninternal.server.deploy; import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebean.bean.EntityBeanIntercept; import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebeaninternal.server.query.SqlJoinType; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java index 0790b87c8..466eba53a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java @@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.deploy; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.BeanCollectionAdd; import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebeaninternal.api.ClassUtil; import com.avaje.ebeaninternal.server.text.json.ReadJson; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java index 343f8e904..f488860e1 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElMatchBuilder.java @@ -4,8 +4,6 @@ import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; -import com.avaje.ebean.bean.EntityBean; - /** * Contains the various ElMatcher implementations. diff --git a/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLLexer.java b/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLLexer.java index 3e15448b1..d65b01136 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLLexer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLLexer.java @@ -1,13 +1,16 @@ // Generated from /home/rob/github/avaje-ebeanorm/src/test/resources/EQL.g4 by ANTLR 4.5.3 package com.avaje.ebeaninternal.server.grammer.antlr; -import org.antlr.v4.runtime.Lexer; + import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.TokenStream; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.RuntimeMetaData; +import org.antlr.v4.runtime.Vocabulary; +import org.antlr.v4.runtime.VocabularyImpl; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.LexerATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.misc.*; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class EQLLexer extends Lexer { diff --git a/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLParser.java b/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLParser.java index f4ede0ebc..7644c2e38 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLParser.java +++ b/src/main/java/com/avaje/ebeaninternal/server/grammer/antlr/EQLParser.java @@ -1,13 +1,23 @@ // Generated from /home/rob/github/avaje-ebeanorm/src/test/resources/EQL.g4 by ANTLR 4.5.3 package com.avaje.ebeaninternal.server.grammer.antlr; -import org.antlr.v4.runtime.atn.*; + +import org.antlr.v4.runtime.NoViableAltException; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.RuntimeMetaData; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.Vocabulary; +import org.antlr.v4.runtime.VocabularyImpl; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.ParserATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.misc.*; -import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.TerminalNode; + import java.util.List; -import java.util.Iterator; -import java.util.ArrayList; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class EQLParser extends Parser { diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java index efd238f73..a53564a20 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java @@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.api.SpiTransaction; import com.avaje.ebeaninternal.api.SpiUpdate; import com.avaje.ebeaninternal.server.core.PersistRequestOrmUpdate; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.type.DataBind; import com.avaje.ebeaninternal.server.util.BindParamsParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java index 67cb2ab4f..30e0ac473 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java @@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.api.SpiSqlUpdate; import com.avaje.ebeaninternal.api.SpiTransaction; import com.avaje.ebeaninternal.server.core.PersistRequestUpdateSql; import com.avaje.ebeaninternal.server.core.PersistRequestUpdateSql.SqlType; -import com.avaje.ebeaninternal.server.type.DataBind; import com.avaje.ebeaninternal.server.util.BindParamsParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableRequest.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableRequest.java index c034e5c78..a81496742 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableRequest.java @@ -1,12 +1,11 @@ package com.avaje.ebeaninternal.server.persist.dmlbind; -import java.sql.SQLException; - -import com.avaje.ebean.bean.EntityBean; import com.avaje.ebeaninternal.api.DerivedRelationshipData; import com.avaje.ebeaninternal.server.core.PersistRequestBean; import com.avaje.ebeaninternal.server.deploy.BeanProperty; +import java.sql.SQLException; + /** * Request object passed to bindables. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java index b989605df..fa7970edf 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java @@ -1,7 +1,6 @@ package com.avaje.ebeaninternal.server.transaction; import com.avaje.ebean.bean.PersistenceContext; -import com.avaje.ebean.bean.PersistenceContextUtil; import com.avaje.ebeaninternal.api.Monitor; import java.util.HashMap; diff --git a/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java b/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java index adb658759..eb4866bb9 100644 --- a/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java +++ b/src/main/java/com/avaje/ebeanservice/docstore/api/support/DocStructure.java @@ -1,9 +1,8 @@ package com.avaje.ebeanservice.docstore.api.support; -import com.avaje.ebean.text.PathProperties; import com.avaje.ebean.FetchPath; +import com.avaje.ebean.text.PathProperties; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc; import java.util.HashMap; From 79b8395f8f3a544d21071c5ad482e2ae7460e14a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:32:37 +1200 Subject: [PATCH 18/65] #794 - Refactor - tidy code, simplify if --- .../server/type/reflect/ImmutableMetaFactory.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/reflect/ImmutableMetaFactory.java b/src/main/java/com/avaje/ebeaninternal/server/type/reflect/ImmutableMetaFactory.java index c40004348..096e5341f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/reflect/ImmutableMetaFactory.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/reflect/ImmutableMetaFactory.java @@ -165,11 +165,7 @@ public class ImmutableMetaFactory { if (methods[i].getParameterTypes().length == 0) { // could be a getter String methName = methods[i].getName(); - if (methName.equals("hashCode")) { - - } else if (methName.equals("toString")) { - - } else { + if (!methName.equals("hashCode") && !methName.equals("toString")) { Class returnType = methods[i].getReturnType(); if (paramType.equals(returnType)) { return methods[i]; From ee0615caecbb4f521a8479f833c29d878589ee58 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:33:07 +1200 Subject: [PATCH 19/65] #794 - Refactor - tidy code, use uppercase L for Long literal --- .../java/com/avaje/ebeaninternal/server/persist/DmlUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/DmlUtil.java b/src/main/java/com/avaje/ebeaninternal/server/persist/DmlUtil.java index 92e99a3fe..df174cfbd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/DmlUtil.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/DmlUtil.java @@ -10,6 +10,6 @@ public class DmlUtil { * Return true if the value is null or a Numeric 0 (for primitive int's and long's) or Option empty. */ public static boolean isNullOrZero(Object value) { - return value == null || value instanceof Number && ((Number) value).longValue() == 0l; + return value == null || value instanceof Number && ((Number) value).longValue() == 0L; } } From dfdf87fa2dfd93c4a2721f9018899c44765f4a5d Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:33:29 +1200 Subject: [PATCH 20/65] #794 - Refactor - tidy code, javadoc tidy --- src/main/java/com/avaje/ebean/SqlUpdate.java | 3 +-- .../server/deploy/parse/AnnotationAssocManys.java | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/avaje/ebean/SqlUpdate.java b/src/main/java/com/avaje/ebean/SqlUpdate.java index 5fe6022a9..c02e89485 100644 --- a/src/main/java/com/avaje/ebean/SqlUpdate.java +++ b/src/main/java/com/avaje/ebean/SqlUpdate.java @@ -117,8 +117,7 @@ public interface SqlUpdate { SqlUpdate setParameter(int position, Object value); /** - * Set a null parameter via its index position. Exactly the same as - * {@link #setNull(int, int)}. + * Set a null parameter via its index position. */ SqlUpdate setNull(int position, int jdbcType); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index e69abc3f1..1e6ebb809 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -170,9 +170,7 @@ public class AnnotationAssocManys extends AnnotationParser { } /** - * Return the full table name - * @param joinTable - * @return + * Return the full table name */ private String getFullTableName(JoinTable joinTable) { StringBuilder sb = new StringBuilder(); From 84a86cad0e6760f4148fd52e2bbd901b67680e2e Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 31 Jul 2016 23:34:55 +1200 Subject: [PATCH 21/65] #794 - Refactor - tidy code, remove unused mimetypes properties --- .../server/lib/util/mimetypes.properties | 186 ------------------ 1 file changed, 186 deletions(-) delete mode 100644 src/main/java/com/avaje/ebeaninternal/server/lib/util/mimetypes.properties diff --git a/src/main/java/com/avaje/ebeaninternal/server/lib/util/mimetypes.properties b/src/main/java/com/avaje/ebeaninternal/server/lib/util/mimetypes.properties deleted file mode 100644 index 8b77c2af1..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/lib/util/mimetypes.properties +++ /dev/null @@ -1,186 +0,0 @@ - # - # Used by MimeTypeHelper to find the mime types of based on file extensions. - -abs=audio/x-mpeg -ai=application/postscript -aif=audio/x-aiff -aifc=audio/x-aiff -aiff=audio/x-aiff -aim=application/x-aim -art=image/x-jg -asc=text/plain -asf=video/x-ms-asf -asx=video/x-ms-asf -au=audio/basic -avi=video/x-msvideo -avx=video/x-rad-screenplay - -bcpio=application/x-bcpio -bin=application/octet-stream -bmp=image/bmp -body=text/html - -cdf=application/x-netcdf -cer=application/x-x509-ca-cert -class=application/java -cpio=application/x-cpio -csh=application/x-csh -css=text/css -csv=text/csv - -dib=image/bmp -doc=application/msword -dtd=application/xml-dtd -dv=video/x-dv -dvi=application/x-dvi -dms=application/octet-stream - -eps=application/postscript -etx=text/x-setext -exe=application/octet-stream - -gif=image/gif -gtar=application/x-gtar -gz=application/x-gzip - -hdf=application/x-hdf -htc=text/x-component -htm=text/html -html=text/html -hqx=application/mac-binhex40 - -ico=image/x-icon -ief=image/ief - -jad=text/vnd.sun.j2me.app-descriptor -jar=application/java-archive -java=text/plain -jnlp=application/x-java-jnlp-file -jpe=image/jpeg -jpeg=image/jpeg -jpg=image/jpeg -js=text/javascript -jsf=text/plain -jspf=text/plain - -kar=audio/midi - -latex=application/x-latex -lha=application/octet-stream -lzh=application/octet-stream - -m3u=audio/x-mpegurl -mac=image/x-macpaint -man=application/x-troff-man -mathml=application/mathml+xml -me=application/x-troff-me -mid=audio/midi -midi=audio/midi -mif=application/vnd.mif -mov=video/quicktime -movie=video/x-sgi-movie -mp1=audio/x-mpeg -mp2=audio/mpeg -mp3=audio/mpeg -mpa=audio/x-mpeg -mpe=video/mpeg -mpeg=video/mpeg -mpega=audio/x-mpeg -mpga=audio/mpeg -mpg=video/mpeg -mpv2=video/mpeg2 -ms=application/x-troff-ms - -nc=application/x-netcdf - -oda=application/oda -ogg=application/ogg - -pbm=image/x-portable-bitmap -pct=image/pict -pdf=application/pdf -pgm=image/x-portable-graymap -pic=image/pict -pict=image/pict -pls=audio/x-scpls -png=image/png -pnm=image/x-portable-anymap -pnt=image/x-macpaint -ppm=image/x-portable-pixmap -pps=application/vnd.ms-powerpoint -ppt=application/vnd.ms-powerpoint -ps=application/postscript -psd=image/x-photoshop - -qt=video/quicktime -qti=image/x-quicktime -qtif=image/x-quicktime - -ra=audio/x-realaudio -ram=audio/x-pn-realaudio -ras=image/x-cmu-raster -rdf=application/rdf+xml -rgb=image/x-rgb -rpm=audio/x-pn-realaudio-plugin -rm=application/vnd.rn-realmedia -roff=application/x-troff -rtf=text/rtf -rtx=text/richtext - -sh=application/x-sh -shar=application/x-shar -shtml=text/x-server-parsed-html -sgml=text/sgml -sgm=text/sgml -smf=audio/x-midi -sit=application/x-stuffit -snd=audio/basic -src=application/x-wais-source -sv4cpio=application/x-sv4cpio -sv4crc=application/x-sv4crc -svg=image/svg+xml -svgz=image/svg -swf=application/x-shockwave-flash - -t=application/x-troff -tar=application/x-tar -tcl=application/x-tcl -tex=application/x-tex -texi=application/x-texinfo -texinfo=application/x-texinfo -tif=image/tiff -tiff=image/tiff -tr=application/x-troff -tsv=text/tab-separated-values -txt=text/plain - -ulw=audio/basic -ustar=application/x-ustar - -vcd=application/x-cdlink -vrml=model/vrml -vsd=application/x-visio -vxml=application/voicexml+xml - -wav=audio/x-wav -wbmp=image/vnd.wap.wbmp -wml=text/vnd.wap.wml -wmlc=application/vnd.wap.wmlc -wmls=text/vnd.wap.wmlscript -wmlscriptc=application/vnd.wap.wmlscriptc -wrl=model/vrml - -xbm=image/x-xbitmap -xht=application/xhtml+xml -xhtml=application/xhtml+xml -xls=application/vnd.ms-excel -xml=application/xml -xpm=image/x-xpixmap -xsl=application/xml -xslt=application/xslt+xml -xul=application/vnd.mozilla.xul+xml -xwd=image/x-xwindowdump - -Z=application/x-compress -z=application/x-compress -zip=application/zip \ No newline at end of file From 4d16cf9caac83ee2cffc9f9aca12f63c1640ed46 Mon Sep 17 00:00:00 2001 From: Matus Zamborsky Date: Mon, 1 Aug 2016 10:13:05 +0200 Subject: [PATCH 22/65] Add check for distinct query when adding id attribute to order clause in paging query --- .../com/avaje/ebeaninternal/server/query/CQueryEngine.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java index 425e488f8..0818ca8ca 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java @@ -300,9 +300,10 @@ public class CQueryEngine { SpiQuery query = request.getQuery(); - if (query.getMaxRows() > 1 || query.getFirstRow() > 0) { + if (!query.isDistinct() && (query.getMaxRows() > 1 || query.getFirstRow() > 0)) { // deemed to be a be a paging query - check that the order by contains // the id property to ensure unique row ordering for predicable paging + // but only in case, this is not a distinct query request.getBeanDescriptor().appendOrderById(query); } From cdad31bd8a69e1b86c10b0cae8c8e37d8988fcb9 Mon Sep 17 00:00:00 2001 From: Matus Zamborsky Date: Mon, 1 Aug 2016 12:20:50 +0200 Subject: [PATCH 23/65] Added test for distinct paging query --- .../tests/query/other/TestQueryDistinct.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java b/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java index 7a7e6040f..a442c3677 100644 --- a/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java +++ b/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java @@ -80,5 +80,32 @@ public class TestQueryDistinct extends BaseTestCase { Assert.assertNull(customer.getAnniversary()); } } + + @Test + public void testPagingQuery() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Customer.class) + .setMaxRows(10) + .setDistinct(true) + .select("name"); + + List customers = query.findList(); + + String generatedSql = query.getGeneratedSql(); + Assert.assertTrue(generatedSql.contains("select distinct t0.name c0 from o_customer t0 limit 10")); + + for (Customer customer : customers) { + + EntityBeanIntercept ebi = ((EntityBean)customer)._ebean_getIntercept(); + Assert.assertTrue(ebi.isDisableLazyLoad()); + Assert.assertNull(ebi.getPersistenceContext()); + + // lazy loading disabled + Assert.assertNull(customer.getId()); + Assert.assertNull(customer.getAnniversary()); + } + } } From e6e6a282454b1a23539ed0862108b3d98b3e3432 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Mon, 1 Aug 2016 22:53:47 +1200 Subject: [PATCH 24/65] No effective change - tidy asserts on TestQueryDistinct (AssertJ string contains etc) --- .../tests/query/other/TestQueryDistinct.java | 52 ++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java b/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java index a442c3677..751bbc73c 100644 --- a/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java +++ b/src/test/java/com/avaje/tests/query/other/TestQueryDistinct.java @@ -1,10 +1,5 @@ package com.avaje.tests.query.other; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; - import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; import com.avaje.ebean.Query; @@ -12,6 +7,14 @@ import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.bean.EntityBeanIntercept; import com.avaje.tests.model.basic.Customer; import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Test; + +import java.util.List; + +import static junit.framework.TestCase.assertNull; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class TestQueryDistinct extends BaseTestCase { @@ -27,17 +30,17 @@ public class TestQueryDistinct extends BaseTestCase { List customers = query.findList(); String generatedSql = query.getGeneratedSql(); - Assert.assertTrue(generatedSql.contains("select distinct t0.name c0 from o_customer t0")); + assertThat(generatedSql).contains("select distinct t0.name c0 from o_customer t0"); for (Customer customer : customers) { EntityBeanIntercept ebi = ((EntityBean)customer)._ebean_getIntercept(); - Assert.assertTrue(ebi.isDisableLazyLoad()); - Assert.assertNull(ebi.getPersistenceContext()); + assertTrue(ebi.isDisableLazyLoad()); + assertNull(ebi.getPersistenceContext()); // lazy loading disabled - Assert.assertNull(customer.getId()); - Assert.assertNull(customer.getAnniversary()); + assertNull(customer.getId()); + assertNull(customer.getAnniversary()); } } @@ -53,7 +56,7 @@ public class TestQueryDistinct extends BaseTestCase { query.findList(); String generatedSql = query.getGeneratedSql(); - Assert.assertTrue(generatedSql.contains("select distinct t0.name c0 from o_customer t0")); + assertThat(generatedSql).contains("select distinct t0.name c0 from o_customer t0"); } @Test @@ -69,20 +72,20 @@ public class TestQueryDistinct extends BaseTestCase { List customers = query.findList(); String generatedSql = query.getGeneratedSql(); - Assert.assertTrue(generatedSql.contains("select distinct t0.status c0 from o_customer t0")); + assertThat(generatedSql).contains("select distinct t0.status c0 from o_customer t0"); for (Customer customer : customers) { - Assert.assertNotNull(customer.getStatus()); + assertNotNull(customer.getStatus()); // lazy loading disabled - Assert.assertNull(customer.getId()); - Assert.assertNull(customer.getAnniversary()); + assertNull(customer.getId()); + assertNull(customer.getAnniversary()); } } @Test - public void testPagingQuery() { + public void testPagingQuery_expect_doesNotAddOrderBy() { ResetBasicData.reset(); @@ -91,20 +94,11 @@ public class TestQueryDistinct extends BaseTestCase { .setDistinct(true) .select("name"); - List customers = query.findList(); + query.findList(); - String generatedSql = query.getGeneratedSql(); - Assert.assertTrue(generatedSql.contains("select distinct t0.name c0 from o_customer t0 limit 10")); - - for (Customer customer : customers) { - - EntityBeanIntercept ebi = ((EntityBean)customer)._ebean_getIntercept(); - Assert.assertTrue(ebi.isDisableLazyLoad()); - Assert.assertNull(ebi.getPersistenceContext()); - - // lazy loading disabled - Assert.assertNull(customer.getId()); - Assert.assertNull(customer.getAnniversary()); + if (isH2() || isPostgres()) { + String generatedSql = query.getGeneratedSql(); + assertThat(generatedSql).contains("select distinct t0.name c0 from o_customer t0 limit 10"); } } From e2ee6e8e98cd4ca9131be7039d9ccf0516a728b4 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 11:06:09 +1200 Subject: [PATCH 25/65] No effective change - update tests with EBasicVer new constructor --- .../java/com/avaje/ebean/BaseTestCase.java | 2 +- .../ebean/EbeanServer_deleteAllByIdTest.java | 4 +- .../ebean/EbeanServer_deleteByIdTest.java | 4 +- .../avaje/ebean/EbeanServer_deleteTest.java | 4 +- .../avaje/ebean/EbeanServer_saveAllTest.java | 4 +- .../event/BeanPersistControllerTest.java | 6 +-- .../avaje/ebean/event/BeanPostLoadTest.java | 3 +- .../com/avaje/tests/basic/TestIUDVanilla.java | 6 +-- .../tests/basic/TestLogTransLogOnError.java | 6 +-- .../batchinsert/TestBatchInsertFlush.java | 47 +++++++++++++++++++ .../tests/cache/TestQueryCacheInsert.java | 4 +- .../TestDeleteWithoutOptimisticLocking.java | 6 +-- .../tests/iud/TestInsertQueryUpdate.java | 3 +- .../tests/iud/TestInsertUpdateTrans.java | 3 +- .../avaje/tests/model/basic/EBasicVer.java | 4 ++ .../TestPersistenceContextQueryScope.java | 3 +- .../TestDeleteFromPersistenceContext.java | 4 +- .../TestTxTypeOnTransactional.java | 3 +- .../avaje/tests/update/TestMarkAsDirty.java | 4 +- .../update/TestUpdateAllLoadedProperties.java | 6 +-- 20 files changed, 75 insertions(+), 51 deletions(-) create mode 100644 src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java diff --git a/src/test/java/com/avaje/ebean/BaseTestCase.java b/src/test/java/com/avaje/ebean/BaseTestCase.java index ab5700445..e6be4834e 100644 --- a/src/test/java/com/avaje/ebean/BaseTestCase.java +++ b/src/test/java/com/avaje/ebean/BaseTestCase.java @@ -13,7 +13,7 @@ public class BaseTestCase { static { logger.debug("... preStart"); - if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent","debug=0;packages=com.avaje.tests.**,org.avaje.test.**")) { + if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent","debug=1;packages=com.avaje.tests,org.avaje.test")) { logger.info("avaje-ebeanorm-agent not found in classpath - not dynamically loaded"); } } diff --git a/src/test/java/com/avaje/ebean/EbeanServer_deleteAllByIdTest.java b/src/test/java/com/avaje/ebean/EbeanServer_deleteAllByIdTest.java index 9e5ce361c..0e3f48ebd 100644 --- a/src/test/java/com/avaje/ebean/EbeanServer_deleteAllByIdTest.java +++ b/src/test/java/com/avaje/ebean/EbeanServer_deleteAllByIdTest.java @@ -114,8 +114,6 @@ public class EbeanServer_deleteAllByIdTest { } private EBasicVer bean(String name) { - EBasicVer bean = new EBasicVer(); - bean.setName(name); - return bean; + return new EBasicVer(name); } } \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/EbeanServer_deleteByIdTest.java b/src/test/java/com/avaje/ebean/EbeanServer_deleteByIdTest.java index a0b3bebf6..987c2c61a 100644 --- a/src/test/java/com/avaje/ebean/EbeanServer_deleteByIdTest.java +++ b/src/test/java/com/avaje/ebean/EbeanServer_deleteByIdTest.java @@ -85,8 +85,6 @@ public class EbeanServer_deleteByIdTest { } private EBasicVer bean(String name) { - EBasicVer bean = new EBasicVer(); - bean.setName(name); - return bean; + return new EBasicVer(name); } } \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/EbeanServer_deleteTest.java b/src/test/java/com/avaje/ebean/EbeanServer_deleteTest.java index 82d377dc6..48d3ce3ba 100644 --- a/src/test/java/com/avaje/ebean/EbeanServer_deleteTest.java +++ b/src/test/java/com/avaje/ebean/EbeanServer_deleteTest.java @@ -48,8 +48,6 @@ public class EbeanServer_deleteTest { } private EBasicVer bean(String name) { - EBasicVer bean = new EBasicVer(); - bean.setName(name); - return bean; + return new EBasicVer(name); } } \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/EbeanServer_saveAllTest.java b/src/test/java/com/avaje/ebean/EbeanServer_saveAllTest.java index 850a420a0..4cdedd009 100644 --- a/src/test/java/com/avaje/ebean/EbeanServer_saveAllTest.java +++ b/src/test/java/com/avaje/ebean/EbeanServer_saveAllTest.java @@ -123,8 +123,6 @@ public class EbeanServer_saveAllTest extends BaseTestCase { } private EBasicVer bean(String name) { - EBasicVer bean = new EBasicVer(); - bean.setName(name); - return bean; + return new EBasicVer(name); } } \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/event/BeanPersistControllerTest.java b/src/test/java/com/avaje/ebean/event/BeanPersistControllerTest.java index c889510e0..5aba15b8a 100644 --- a/src/test/java/com/avaje/ebean/event/BeanPersistControllerTest.java +++ b/src/test/java/com/avaje/ebean/event/BeanPersistControllerTest.java @@ -24,8 +24,7 @@ public class BeanPersistControllerTest { EbeanServer ebeanServer = getEbeanServer(continuePersistingAdapter); - EBasicVer bean = new EBasicVer(); - bean.setName("testController"); + EBasicVer bean = new EBasicVer("testController"); ebeanServer.save(bean); assertThat(continuePersistingAdapter.methodsCalled).hasSize(2); @@ -49,8 +48,7 @@ public class BeanPersistControllerTest { EbeanServer ebeanServer = getEbeanServer(stopPersistingAdapter); - EBasicVer bean = new EBasicVer(); - bean.setName("testController"); + EBasicVer bean = new EBasicVer("testController"); ebeanServer.save(bean); assertThat(stopPersistingAdapter.methodsCalled).hasSize(1); diff --git a/src/test/java/com/avaje/ebean/event/BeanPostLoadTest.java b/src/test/java/com/avaje/ebean/event/BeanPostLoadTest.java index 2372e3c1e..1e782cc67 100644 --- a/src/test/java/com/avaje/ebean/event/BeanPostLoadTest.java +++ b/src/test/java/com/avaje/ebean/event/BeanPostLoadTest.java @@ -24,8 +24,7 @@ public class BeanPostLoadTest extends BaseTestCase { EbeanServer ebeanServer = getEbeanServer(); - EBasicVer bean = new EBasicVer(); - bean.setName("testPostLoad"); + EBasicVer bean = new EBasicVer("testPostLoad"); bean.setDescription("someDescription"); bean.setOther("other"); diff --git a/src/test/java/com/avaje/tests/basic/TestIUDVanilla.java b/src/test/java/com/avaje/tests/basic/TestIUDVanilla.java index 0cb0b2b7d..2b9d1e3d8 100644 --- a/src/test/java/com/avaje/tests/basic/TestIUDVanilla.java +++ b/src/test/java/com/avaje/tests/basic/TestIUDVanilla.java @@ -14,8 +14,7 @@ public class TestIUDVanilla extends BaseTestCase { @Test public void test() { - EBasicVer e0 = new EBasicVer(); - e0.setName("vanilla"); + EBasicVer e0 = new EBasicVer("vanilla"); Ebean.save(e0); @@ -39,9 +38,8 @@ public class TestIUDVanilla extends BaseTestCase { e2.setName("forcedUpdate"); Ebean.update(e2); - EBasicVer e3 = new EBasicVer(); + EBasicVer e3 = new EBasicVer("ModNoOCC"); e3.setId(e0.getId()); - e3.setName("ModNoOCC"); Ebean.update(e3); diff --git a/src/test/java/com/avaje/tests/basic/TestLogTransLogOnError.java b/src/test/java/com/avaje/tests/basic/TestLogTransLogOnError.java index 9f53c0f65..58a8368d5 100644 --- a/src/test/java/com/avaje/tests/basic/TestLogTransLogOnError.java +++ b/src/test/java/com/avaje/tests/basic/TestLogTransLogOnError.java @@ -25,9 +25,8 @@ public class TestLogTransLogOnError extends BaseTestCase { Ebean.find(Customer.class).findList(); Ebean.find(Order.class).where().gt("id", 1).findList(); - EBasicVer newBean = new EBasicVer(); + EBasicVer newBean = new EBasicVer("aName"); newBean.setDescription("something"); - newBean.setName("aName"); // Ebean.save(newBean); @@ -55,13 +54,12 @@ public class TestLogTransLogOnError extends BaseTestCase { try { Ebean.find(Customer.class).findList(); - EBasicVer newBean = new EBasicVer(); + EBasicVer newBean = new EBasicVer("aName"); newBean .setDescription("something sdfjksdjflsjdflsjdflksjdfkjd fsjdfkjsdkfjsdkfjskdjfskjdf" + " sjdf sdjflksjdfkjsdlfkjsdkfjs ksjdfksjdlfjsldf something sdfjksdjflsjdflsjdflksjdfkjd" + "fsjdfkjsdkfjsdkfjskdjfskjdf sjdf sdjflksjdfkjsdlfkjsdkfjs ksjdfksjdlfjsldf something s" + "dfjksdjflsjdflsjdflksjdfkjd fsjdfkjsdkfjsdkfjskdjfskjdf sjdf sdjflksjdfkjsdlfkjsdkfjs "); - newBean.setName("aName"); // t.log("--- next insert should error"); Ebean.save(newBean); diff --git a/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java b/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java new file mode 100644 index 000000000..ed5fc8892 --- /dev/null +++ b/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java @@ -0,0 +1,47 @@ +package com.avaje.tests.batchinsert; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.EbeanServer; +import com.avaje.ebean.Transaction; +import com.avaje.ebean.config.PersistBatch; +import com.avaje.tests.model.basic.EBasicVer; +import org.junit.Test; + +import java.sql.Timestamp; + +public class TestBatchInsertFlush extends BaseTestCase { + + @Test + public void testFlushOnGetId() { + + EbeanServer server = Ebean.getDefaultServer(); + Transaction txn = server.beginTransaction(); + try { + txn.setBatch(PersistBatch.ALL); + + EBasicVer b1 = new EBasicVer("b1"); + server.save(b1, txn); + + EBasicVer b2 = new EBasicVer("b2"); + server.save(b2, txn); + + //txn.flushBatch(); + + b1.setDescription("modify"); + System.out.println("here"); + Timestamp lastUpdate = b1.getLastUpdate(); + Integer id = b1.getId(); + + EBasicVer b3 = new EBasicVer("b3"); + server.save(b3, txn); + + txn.commit(); + + } finally { + txn.end(); + } + + + } +} diff --git a/src/test/java/com/avaje/tests/cache/TestQueryCacheInsert.java b/src/test/java/com/avaje/tests/cache/TestQueryCacheInsert.java index 82ad9f308..966effe01 100644 --- a/src/test/java/com/avaje/tests/cache/TestQueryCacheInsert.java +++ b/src/test/java/com/avaje/tests/cache/TestQueryCacheInsert.java @@ -17,12 +17,12 @@ public class TestQueryCacheInsert extends BaseTestCase { EbeanServer server = Ebean.getServer(null); - EBasicVer account = new EBasicVer(); + EBasicVer account = new EBasicVer("junk"); server.save(account); List alist0 = server.find(EBasicVer.class).setUseQueryCache(true).findList(); - EBasicVer a2 = new EBasicVer(); + EBasicVer a2 = new EBasicVer("junk2"); server.save(a2); awaitL2Cache(); diff --git a/src/test/java/com/avaje/tests/delete/TestDeleteWithoutOptimisticLocking.java b/src/test/java/com/avaje/tests/delete/TestDeleteWithoutOptimisticLocking.java index 8487789db..51d0981b4 100644 --- a/src/test/java/com/avaje/tests/delete/TestDeleteWithoutOptimisticLocking.java +++ b/src/test/java/com/avaje/tests/delete/TestDeleteWithoutOptimisticLocking.java @@ -31,8 +31,7 @@ public class TestDeleteWithoutOptimisticLocking extends BaseTestCase { @Test public void testSimpleBeanDelete_existingBean_returnsTrue() { - EBasicVer basic = new EBasicVer(); - basic.setName("DelTest"); + EBasicVer basic = new EBasicVer("DelTest"); Ebean.save(basic); EBasicVer basicRef = Ebean.getReference(EBasicVer.class, basic.getId()); @@ -43,8 +42,7 @@ public class TestDeleteWithoutOptimisticLocking extends BaseTestCase { @Test public void testSimpleBeanDelete_existingBeanWithJdbcBatch_returnsTrue() { - EBasicVer basic = new EBasicVer(); - basic.setName("DelTestBatch"); + EBasicVer basic = new EBasicVer("DelTestBatch"); Ebean.save(basic); EbeanServer server = Ebean.getDefaultServer(); diff --git a/src/test/java/com/avaje/tests/iud/TestInsertQueryUpdate.java b/src/test/java/com/avaje/tests/iud/TestInsertQueryUpdate.java index 58fa4375c..e4eaf5894 100644 --- a/src/test/java/com/avaje/tests/iud/TestInsertQueryUpdate.java +++ b/src/test/java/com/avaje/tests/iud/TestInsertQueryUpdate.java @@ -15,8 +15,7 @@ public class TestInsertQueryUpdate extends BaseTestCase { @Test public void test() { - EBasicVer e0 = new EBasicVer(); - e0.setName("name0"); + EBasicVer e0 = new EBasicVer("name0"); e0.setDescription("desc0"); Ebean.save(e0); diff --git a/src/test/java/com/avaje/tests/iud/TestInsertUpdateTrans.java b/src/test/java/com/avaje/tests/iud/TestInsertUpdateTrans.java index 8d50beba1..6c71a44ab 100644 --- a/src/test/java/com/avaje/tests/iud/TestInsertUpdateTrans.java +++ b/src/test/java/com/avaje/tests/iud/TestInsertUpdateTrans.java @@ -15,8 +15,7 @@ public class TestInsertUpdateTrans extends BaseTestCase { Ebean.beginTransaction(); try { - EBasicVer e0 = new EBasicVer(); - e0.setName("onInsert"); + EBasicVer e0 = new EBasicVer("onInsert"); e0.setDescription("something"); Ebean.save(e0); diff --git a/src/test/java/com/avaje/tests/model/basic/EBasicVer.java b/src/test/java/com/avaje/tests/model/basic/EBasicVer.java index 95975f337..7c63183ef 100644 --- a/src/test/java/com/avaje/tests/model/basic/EBasicVer.java +++ b/src/test/java/com/avaje/tests/model/basic/EBasicVer.java @@ -25,6 +25,10 @@ public class EBasicVer { @Version Timestamp lastUpdate; + public EBasicVer(String name) { + this.name = name; + } + public Integer getId() { return id; } diff --git a/src/test/java/com/avaje/tests/persistencecontext/TestPersistenceContextQueryScope.java b/src/test/java/com/avaje/tests/persistencecontext/TestPersistenceContextQueryScope.java index ee036322b..1a2cd85ce 100644 --- a/src/test/java/com/avaje/tests/persistencecontext/TestPersistenceContextQueryScope.java +++ b/src/test/java/com/avaje/tests/persistencecontext/TestPersistenceContextQueryScope.java @@ -16,8 +16,7 @@ public class TestPersistenceContextQueryScope extends BaseTestCase { @Test public void test() { - EBasicVer bean = new EBasicVer(); - bean.setName("first"); + EBasicVer bean = new EBasicVer("first"); Ebean.save(bean); //Ebean.getServerCacheManager().setCaching(EBasicVer.class, true); diff --git a/src/test/java/com/avaje/tests/transaction/TestDeleteFromPersistenceContext.java b/src/test/java/com/avaje/tests/transaction/TestDeleteFromPersistenceContext.java index 15050e22c..79d26407b 100644 --- a/src/test/java/com/avaje/tests/transaction/TestDeleteFromPersistenceContext.java +++ b/src/test/java/com/avaje/tests/transaction/TestDeleteFromPersistenceContext.java @@ -18,9 +18,7 @@ public class TestDeleteFromPersistenceContext extends BaseTestCase { ResetBasicData.reset(); - EBasicVer bean = new EBasicVer(); - bean.setName("Please Delete Me"); - + EBasicVer bean = new EBasicVer("Please Delete Me"); Ebean.save(bean); SpiTransaction transaction = (SpiTransaction)Ebean.beginTransaction(); diff --git a/src/test/java/com/avaje/tests/unitinternal/TestTxTypeOnTransactional.java b/src/test/java/com/avaje/tests/unitinternal/TestTxTypeOnTransactional.java index ddecf3197..63a76739a 100644 --- a/src/test/java/com/avaje/tests/unitinternal/TestTxTypeOnTransactional.java +++ b/src/test/java/com/avaje/tests/unitinternal/TestTxTypeOnTransactional.java @@ -39,8 +39,7 @@ public class TestTxTypeOnTransactional extends BaseTestCase { public void testOptimisticException() { logger.info("-- testOptimisticException"); - EBasicVer v = new EBasicVer(); - v.setName("occ"); + EBasicVer v = new EBasicVer("occ"); v.setDescription("blah"); Ebean.save(v); diff --git a/src/test/java/com/avaje/tests/update/TestMarkAsDirty.java b/src/test/java/com/avaje/tests/update/TestMarkAsDirty.java index dbca56a69..789ec6e1d 100644 --- a/src/test/java/com/avaje/tests/update/TestMarkAsDirty.java +++ b/src/test/java/com/avaje/tests/update/TestMarkAsDirty.java @@ -14,9 +14,7 @@ public class TestMarkAsDirty extends BaseTestCase { @Test public void test() throws InterruptedException { - EBasicVer bean = new EBasicVer(); - bean.setName("markAsDirty"); - + EBasicVer bean = new EBasicVer("markAsDirty"); Ebean.save(bean); Timestamp lastUpdate = bean.getLastUpdate(); diff --git a/src/test/java/com/avaje/tests/update/TestUpdateAllLoadedProperties.java b/src/test/java/com/avaje/tests/update/TestUpdateAllLoadedProperties.java index 8e83930aa..a02782991 100644 --- a/src/test/java/com/avaje/tests/update/TestUpdateAllLoadedProperties.java +++ b/src/test/java/com/avaje/tests/update/TestUpdateAllLoadedProperties.java @@ -20,13 +20,11 @@ public class TestUpdateAllLoadedProperties extends BaseTestCase { @Test public void test() { - EBasicVer basic1 = new EBasicVer(); - basic1.setName("basic1"); + EBasicVer basic1 = new EBasicVer("basic1"); basic1.setDescription("aaa"); Ebean.save(basic1); - EBasicVer basic2 = new EBasicVer(); - basic1.setName("basic2"); + EBasicVer basic2 = new EBasicVer("basic2"); basic1.setDescription("bbb"); Ebean.save(basic2); From 48edf64013387e9a618989c408f79473afa763e6 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 11:10:19 +1200 Subject: [PATCH 26/65] No effective change - typo in javadoc --- .../com/avaje/ebeaninternal/server/persist/BatchControl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java b/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java index c76277461..846ed3dd2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java @@ -146,7 +146,7 @@ public final class BatchControl { /** * Entity Bean insert, update or delete. This will either execute the request - * immediately or queue it for batch processing later. The queue is flushed + * immediately or queue it for batch processing later. The queue is flushedIntercept * according to the depth (object graph depth). */ public int executeOrQueue(PersistRequestBean request, boolean batch) { From dacdc2690278828b0d6566394082515f26b21c4b Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 16:16:34 +1200 Subject: [PATCH 27/65] #798 - ENH: Add support for transparent full JDBC batch. Via enhancement agent 8.1.1 intercept bean getter to automatically flush the JDBC batch buffer. --- pom.xml | 4 +- .../avaje/ebean/bean/EntityBeanIntercept.java | 35 ++++++++++- .../avaje/ebean/bean/PreGetterCallback.java | 13 ++++ .../server/core/PersistRequestBean.java | 20 +++++- .../server/deploy/id/IdBinderSimple.java | 2 - .../batchinsert/TestBatchInsertFlush.java | 61 +++++++++++++++++-- .../basic/xtra/TestInsertBatchThenUpdate.java | 17 +++--- 7 files changed, 130 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/avaje/ebean/bean/PreGetterCallback.java diff --git a/pom.xml b/pom.xml index 2bc032908..7adc9a211 100644 --- a/pom.xml +++ b/pom.xml @@ -174,7 +174,7 @@ org.avaje.ebeanorm avaje-ebeanorm-agent - 4.11.1 + 4.12.1-SNAPSHOT test @@ -249,7 +249,7 @@ org.avaje.ebeanorm avaje-ebeanorm-mavenenhancer - 4.11.1 + 4.12.1-SNAPSHOT test diff --git a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java index 24462e614..1f9af8aa9 100644 --- a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java @@ -39,6 +39,8 @@ public final class EntityBeanIntercept implements Serializable { private transient BeanLoader beanLoader; + private transient PreGetterCallback preGetterCallback; + private String ebeanServerName; /** @@ -186,6 +188,21 @@ public final class EntityBeanIntercept implements Serializable { return embeddedOwnerIndex; } + /** + * Clear the getter callback. + */ + public void clearGetterCallback() { + this.preGetterCallback = null; + } + + /** + * Register the callback to be triggered when getter is called. + * This is used primarily to automatically flush the JDBC batch. + */ + public void registerGetterCallback(PreGetterCallback getterCallback) { + this.preGetterCallback = getterCallback; + } + /** * Set the embedded beans owning bean. */ @@ -832,19 +849,31 @@ public final class EntityBeanIntercept implements Serializable { public void initialisedMany(int propertyIndex) { loadedProps[propertyIndex] = true; } - + + private final void preGetterCallback() { + if (preGetterCallback != null) { + preGetterCallback.preGetterTrigger(); + } + } + + /** + * Called prior to Id property getter. + */ + public void preGetId() { + preGetterCallback(); + } + /** * Method that is called prior to a getter method on the actual entity. */ public void preGetter(int propertyIndex) { + preGetterCallback(); if (state == STATE_NEW || disableLazyLoad) { return; } - if (!isLoadedProperty(propertyIndex)) { loadBean(propertyIndex); } - if (nodeUsageCollector != null) { nodeUsageCollector.addUsed(getProperty(propertyIndex)); } diff --git a/src/main/java/com/avaje/ebean/bean/PreGetterCallback.java b/src/main/java/com/avaje/ebean/bean/PreGetterCallback.java new file mode 100644 index 000000000..8faecec22 --- /dev/null +++ b/src/main/java/com/avaje/ebean/bean/PreGetterCallback.java @@ -0,0 +1,13 @@ +package com.avaje.ebean.bean; + +/** + * A callback that can be registered to fire on getter method calls. + * It's primary purpose is to automatically flush JDBC batch buffer. + */ +public interface PreGetterCallback { + + /** + * Trigger the callback. + */ + void preGetterTrigger(); +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java index afd86bfa6..55c997538 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java @@ -1,6 +1,7 @@ package com.avaje.ebeaninternal.server.core; import com.avaje.ebean.ValuePair; +import com.avaje.ebean.bean.PreGetterCallback; import com.avaje.ebeaninternal.api.ConcurrencyMode; import com.avaje.ebean.annotation.DocStoreMode; import com.avaje.ebean.bean.EntityBean; @@ -36,7 +37,7 @@ import java.util.Set; /** * PersistRequest for insert update or delete of a bean. */ -public final class PersistRequestBean extends PersistRequest implements BeanPersistRequest, DocStoreUpdate { +public final class PersistRequestBean extends PersistRequest implements BeanPersistRequest, DocStoreUpdate, PreGetterCallback { private final BeanManager beanManager; @@ -137,6 +138,11 @@ public final class PersistRequestBean extends PersistRequest implements BeanP private long version; + /** + * Flag set when request is added to JDBC batch registered as a "getter callback" to automatically flush batch. + */ + private boolean getterCallback; + public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager mgr, SpiTransaction t, PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse, boolean publish) { @@ -239,8 +245,17 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ public void setBatched() { batched = true; + if (type == Type.INSERT || type == Type.UPDATE) { + // used to trigger automatic jdbc batch flush + intercept.registerGetterCallback(this); + getterCallback = true; + } } + @Override + public void preGetterTrigger() { + transaction.flushBatch(); + } public void setSkipBatchForTopLevel() { skipBatchForTopLevel = true; @@ -621,6 +636,9 @@ public final class PersistRequestBean extends PersistRequest implements BeanP @Override public int executeNow() { + if (getterCallback) { + intercept.clearGetterCallback(); + } switch (type) { case INSERT: persistExecute.executeInsertBean(this); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/IdBinderSimple.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/IdBinderSimple.java index 0a3f05474..aa677d98b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/IdBinderSimple.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/IdBinderSimple.java @@ -217,12 +217,10 @@ public final class IdBinderSimple implements IdBinder { if (!idValue.getClass().equals(expectedType)) { idValue = scalarType.toBeanType(idValue); } - if (bean != null) { // support PropertyChangeSupport idProperty.setValueIntercept(bean, idValue); } - return idValue; } } diff --git a/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java b/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java index ed5fc8892..141da0b3c 100644 --- a/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java +++ b/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java @@ -10,6 +10,8 @@ import org.junit.Test; import java.sql.Timestamp; +import static org.junit.Assert.assertNotNull; + public class TestBatchInsertFlush extends BaseTestCase { @Test @@ -26,12 +28,8 @@ public class TestBatchInsertFlush extends BaseTestCase { EBasicVer b2 = new EBasicVer("b2"); server.save(b2, txn); - //txn.flushBatch(); - - b1.setDescription("modify"); - System.out.println("here"); - Timestamp lastUpdate = b1.getLastUpdate(); Integer id = b1.getId(); + assertNotNull(id); EBasicVer b3 = new EBasicVer("b3"); server.save(b3, txn); @@ -41,7 +39,60 @@ public class TestBatchInsertFlush extends BaseTestCase { } finally { txn.end(); } + } + @Test + public void testFlushOnGetProperty() { + EbeanServer server = Ebean.getDefaultServer(); + Transaction txn = server.beginTransaction(); + try { + txn.setBatch(PersistBatch.ALL); + + EBasicVer b1 = new EBasicVer("b1"); + server.save(b1, txn); + + EBasicVer b2 = new EBasicVer("b2"); + server.save(b2, txn); + + // flush here + Timestamp lastUpdate = b1.getLastUpdate(); + assertNotNull(lastUpdate); + + EBasicVer b3 = new EBasicVer("b3"); + server.save(b3, txn); + + txn.commit(); + + } finally { + txn.end(); + } + } + + @Test + public void testFlushOnSetProperty() { + + EbeanServer server = Ebean.getDefaultServer(); + Transaction txn = server.beginTransaction(); + try { + txn.setBatch(PersistBatch.ALL); + + EBasicVer b1 = new EBasicVer("b1"); + server.save(b1, txn); + + EBasicVer b2 = new EBasicVer("b2"); + server.save(b2, txn); + + // flush here + b1.setDescription("modify"); + + EBasicVer b3 = new EBasicVer("b3"); + server.save(b3, txn); + + txn.commit(); + + } finally { + txn.end(); + } } } diff --git a/src/test/java/com/avaje/tests/model/basic/xtra/TestInsertBatchThenUpdate.java b/src/test/java/com/avaje/tests/model/basic/xtra/TestInsertBatchThenUpdate.java index 617cc1e95..a9c22e64c 100644 --- a/src/test/java/com/avaje/tests/model/basic/xtra/TestInsertBatchThenUpdate.java +++ b/src/test/java/com/avaje/tests/model/basic/xtra/TestInsertBatchThenUpdate.java @@ -10,6 +10,7 @@ import org.junit.Test; import java.util.ArrayList; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; public class TestInsertBatchThenUpdate extends BaseTestCase { @@ -24,6 +25,8 @@ public class TestInsertBatchThenUpdate extends BaseTestCase { try { txn.setBatch(PersistBatch.ALL); + LoggedSqlCollector.start(); + EdParent parent = new EdParent(); parent.setName("MyComputer"); @@ -36,21 +39,17 @@ public class TestInsertBatchThenUpdate extends BaseTestCase { Ebean.save(parent); - // nothing flushed yet - List loggedSql0 = LoggedSqlCollector.start(); - assertEquals(0, loggedSql0.size()); - parent.setName("MyDesk"); Ebean.save(parent); - // nothing flushed yet - assertEquals(0, LoggedSqlCollector.start().size()); - Ebean.commitTransaction(); // insert statements for EdExtendedParent - List loggedSql2 = LoggedSqlCollector.start(); - assertEquals(2, loggedSql2.size()); + List loggedSql = LoggedSqlCollector.stop(); + assertEquals(3, loggedSql.size()); + assertThat(loggedSql.get(0)).contains("insert into td_parent"); + assertThat(loggedSql.get(1)).contains("insert into td_child "); + assertThat(loggedSql.get(2)).contains("update td_parent set parent_name=? where parent_id=?"); } finally { Ebean.endTransaction(); From baa6fc355e39e17fd451aad3f00375e86ab38459 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 20:14:07 +1200 Subject: [PATCH 28/65] No effective change - javadoc update on FetchConfig --- src/main/java/com/avaje/ebean/FetchConfig.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/avaje/ebean/FetchConfig.java b/src/main/java/com/avaje/ebean/FetchConfig.java index bf2904531..fc4f3de11 100644 --- a/src/main/java/com/avaje/ebean/FetchConfig.java +++ b/src/main/java/com/avaje/ebean/FetchConfig.java @@ -29,8 +29,7 @@ import java.io.Serializable; * // Find Orders join details using a single SQL query * } *

- * Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL - * queries + * Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries *

* *
{@code
@@ -117,7 +116,7 @@ import java.io.Serializable;
  * 
{@code
  * List list = Ebean.find(Order.class)
  *   .fetch("customer","name", new FetchConfig().lazy(5))
- *   .fetch("customer.contacts","contactName, phone, email")
+ *   .fetch("customer.contacts","contactName, phone, email")
  *   .fetch("customer.shippingAddress")
  *   .where().eq("status",Order.Status.NEW)
  *   .findList();
@@ -125,12 +124,7 @@ import java.io.Serializable;
  * // query 1) find order where status = Order.Status.NEW
  * //  
  * // .. if lazy loading of customers is invoked 
- * // .. use a batch size of 5 to load the customers 
- *  
- *       find  customer (name) 
- *       fetch customer.contacts (contactName, phone, email) 
- *       fetch customer.shippingAddress (*) 
- *       where id in (?,?,?,?,?)
+ * // .. use a batch size of 5 to load the customers
  * 
  * }
* From ca1c0a08f3b537aa3e9c8d01ad6a6b4161496bdb Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 20:14:46 +1200 Subject: [PATCH 29/65] No effective change - remove whitespace on DLoadBeanContext --- .../ebeaninternal/server/loadcontext/DLoadBeanContext.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java index 09cd0419a..3a73be4e3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java @@ -25,9 +25,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex private LoadBuffer currentBuffer; public DLoadBeanContext(DLoadContext parent, BeanDescriptor desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) { - super(parent, desc, path, defaultBatchSize, queryProps); - // bufferList only required when using query joins (queryFetch) this.bufferList = (!queryFetch) ? null : new ArrayList(); this.currentBuffer = createBuffer(firstBatchSize); From 6e2148d20b71fe913019422c8587fa2c7a79d3ed Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 20:19:38 +1200 Subject: [PATCH 30/65] #799 - Query.fetch(path) when converted to query join default to batchSize 10 rather than 100 --- .../server/loadcontext/DLoadBaseContext.java | 2 -- .../server/loadcontext/DLoadContext.java | 23 +++++++++++-------- .../server/loadcontext/DLoadContextTest.java | 15 ++++++++++++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBaseContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBaseContext.java index 249d9f998..72bc67626 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBaseContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBaseContext.java @@ -56,11 +56,9 @@ public abstract class DLoadBaseContext { int queryBatchSize = queryProps.getQueryFetchBatch(); if (queryBatchSize == -1) { - // not eager query fetch, just lazy loading return batchSize; } else if (queryBatchSize == 0) { - // default query fetch batch size is 100 return 100; } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java index fde0ebde4..2088e5b05 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java @@ -284,20 +284,23 @@ public class DLoadContext implements LoadContext { private void registerSecondaryNode(boolean many, OrmQueryProperties props) { - String path = props.getPath(); - int lazyJoinBatch = props.getLazyFetchBatch(); - int batchSize = lazyJoinBatch > 0 ? lazyJoinBatch : defaultBatchSize; - - if (many) { - DLoadManyContext manyContext = createManyContext(path, batchSize, props); - manyMap.put(path, manyContext); + int batchSize; + if (props.isQueryFetch()) { + batchSize = 100; } else { - DLoadBeanContext beanContext = createBeanContext(path, batchSize, props); - beanMap.put(path, beanContext); + int lazyJoinBatch = props.getLazyFetchBatch(); + batchSize = lazyJoinBatch > 0 ? lazyJoinBatch : defaultBatchSize; + } + + String path = props.getPath(); + if (many) { + manyMap.put(path, createManyContext(path, batchSize, props)); + } else { + beanMap.put(path, createBeanContext(path, batchSize, props)); } } - private DLoadManyContext getManyContext(String path) { + protected DLoadManyContext getManyContext(String path) { if (path == null) { throw new RuntimeException("path is null?"); } diff --git a/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java b/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java index 006544217..e81c52d48 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java @@ -77,4 +77,19 @@ public class DLoadContextTest extends BaseTestCase { assertThat(customer.secondaryBatchSize).isEqualTo(5); } + @Test + public void construct_when_fetch_expect_100_100_batchSize() { + + // the fetch is converted to a query join due to the maxRows + OrmQueryRequest queryRequest = queryRequest(query().fetch("details").setMaxRows(100)) ; + queryRequest.initTransIfRequired(); + queryRequest.endTransIfRequired(); + + DLoadContext graphContext = (DLoadContext)queryRequest.getGraphContext(); + DLoadManyContext details = graphContext.getManyContext("details"); + + assertThat(details.firstBatchSize).isEqualTo(100); + assertThat(details.secondaryBatchSize).isEqualTo(100); + } + } \ No newline at end of file From cbcec8f5ea13f8a98e2d6f14723ffd6410e8d54c Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 20:32:59 +1200 Subject: [PATCH 31/65] No effective change - tidy --- .../server/querydefn/OrmQueryPlanKey.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java index 11b1c6616..60b15fe5d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/OrmQueryPlanKey.java @@ -16,7 +16,6 @@ public class OrmQueryPlanKey implements CQueryPlanKey { private final String m2mIncludeTable; private final String orderByAsSting; - private final OrmQueryDetail detail; private final SpiExpression where; private final SpiExpression having; private final RawSql.Key rawSqlKey; @@ -36,11 +35,10 @@ public class OrmQueryPlanKey implements CQueryPlanKey { private final int planHash; private final int bindCount; - public OrmQueryPlanKey(TableJoin includeTableJoin, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) { + public OrmQueryPlanKey(TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) { - this.m2mIncludeTable = includeTableJoin == null ? null : includeTableJoin.getTable(); + this.m2mIncludeTable = m2mIncludeTable == null ? null : m2mIncludeTable.getTable(); this.type = type; - this.detail = detail; this.maxRows = maxRows; this.firstRow = firstRow; this.disableLazyLoading = disableLazyLoading; @@ -69,7 +67,7 @@ public class OrmQueryPlanKey implements CQueryPlanKey { builder.add(hasIdValue); builder.add(temporalMode); builder.add(rawSqlKey == null ? 0 : rawSqlKey.hashCode()); - builder.add(m2mIncludeTable); + builder.add(this.m2mIncludeTable); builder.add(rootTableAlias); if (detail != null) { @@ -126,9 +124,6 @@ public class OrmQueryPlanKey implements CQueryPlanKey { if (having != null ? !having.isSameByPlan(that.having) : that.having != null) return false; if (updateProperties != null ? !updateProperties.isSameByPlan(that.updateProperties) : that.updateProperties != null) return false; if (rawSqlKey != null ? !rawSqlKey.equals(that.rawSqlKey) : that.rawSqlKey != null) return false; - -// if (detail != null ? !detail.equals(that.detail) : that.detail != null) return false; - if (mapKey != null ? !mapKey.equals(that.mapKey) : that.mapKey != null) return false; return rootTableAlias != null ? rootTableAlias.equals(that.rootTableAlias) : that.rootTableAlias == null; } From ad992d07ce6557d355d91969070150594112be60 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 21:31:47 +1200 Subject: [PATCH 32/65] [maven-release-plugin] prepare release avaje-ebeanorm-7.21.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2bc032908..822be219d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 7.21.2-SNAPSHOT + 7.21.2 jar avaje-ebeanorm @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - HEAD + avaje-ebeanorm-7.21.2 From 16950a564105ed61b655a7fec66d4ceff0e44178 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 21:32:08 +1200 Subject: [PATCH 33/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 822be219d..4ea495c50 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 7.21.2 + 7.21.3-SNAPSHOT jar avaje-ebeanorm @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - avaje-ebeanorm-7.21.2 + HEAD From 3657d0577490dd251168445f40006fa975932068 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 21:41:13 +1200 Subject: [PATCH 34/65] #798 - ENH: Add support for transparent full JDBC batch. Via enhancement agent 8.1.1 ... --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index e58258676..08a05d616 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 7.21.3-SNAPSHOT + 8.1.1-SNAPSHOT jar avaje-ebeanorm @@ -174,7 +174,7 @@ org.avaje.ebeanorm avaje-ebeanorm-agent - 4.12.1-SNAPSHOT + 8.1.1 test @@ -249,7 +249,7 @@ org.avaje.ebeanorm avaje-ebeanorm-mavenenhancer - 4.12.1-SNAPSHOT + 8.1.1 test From b5d6c5f70bdad879ad57eef457d3edbe9500520a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 23:30:04 +1200 Subject: [PATCH 35/65] #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use --- src/main/java/com/avaje/ebean/Query.java | 148 +++++++++++++++--- .../server/querydefn/DefaultOrmQuery.java | 24 +++ 2 files changed, 152 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index f860cd11c..3161ef96b 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -371,11 +371,13 @@ public interface Query { Query setDisableReadAuditing(); /** - * Explicitly set a comma delimited list of the properties to fetch on the - * 'main' root level entity bean (aka partial object). Note that '*' means all - * properties. + * Specify the properties to fetch on the root level entity bean in comma delimited format. *

- * You use {@link #fetch(String, String)} to specify specific properties to fetch + * The Id property is automatically included in the properties to fetch unless setDistinct(true) + * is set on the query. + *

+ *

+ * Use {@link #fetch(String, String)} to specify specific properties to fetch * on other non-root level paths of the object graph. *

*
{@code
@@ -395,21 +397,17 @@ public interface Query {
   Query select(String fetchProperties);
 
   /**
-   * Specify a path to fetch with its specific properties to include
-   * (aka partial object).
+   * Specify a path to fetch eagerly including specific properties.
    * 

- * When you specify a join this means that property (associated bean(s)) will - * be fetched and populated. If you specify "*" then all the properties of the - * associated bean will be fetched and populated. You can specify a comma - * delimited list of the properties of that associated bean which means that - * only those properties are fetched and populated resulting in a - * "Partial Object" - a bean that only has some of its properties populated. + * Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can + * not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean + * will automatically convert this fetch query into a "query join" - i.e. use fetchQuery(). *

*
{@code
    *
    * // query orders...
    * List orders =
-   *     ebeanserver.find(Order.class)
+   *     ebeanServer.find(Order.class)
    *       // fetch the customer...
    *       // ... getting the customers name and phone number
    *       .fetch("customer", "name, phoneNumber")
@@ -419,8 +417,7 @@ public interface Query {
    *       .findList();
    * }
*

- * If columns is null or "*" then all columns/properties for that path are - * fetched. + * If columns is null or "*" then all columns/properties for that path are fetched. *

*
{@code
    *
@@ -433,12 +430,62 @@ public interface Query {
    *
    * }
* - * @param path the path of an associated (1-1,1-M,M-1,M-M) bean. + * @param path the property path we wish to fetch eagerly. * @param fetchProperties properties of the associated bean that you want to include in the * fetch (* means all properties, null also means all properties). */ Query fetch(String path, String fetchProperties); + /** + * Fetch the path and properties using a "query join" (separate SQL query). + *

+ * This is the same as: + *

+ *
{@code
+   *
+   *  fetch(path, fetchProperties, new FetchConfig().query())
+   *
+   * }
+ *

+ * This would be used instead of a fetch() when we use a separate SQL query to fetch this + * part of the object graph rather than a SQL join. + *

+ *

+ * We might typically get a performance benefit when the path to fetch is a OneToMany + * or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many + * is high. + *

+ * + * @param path the property path we wish to fetch eagerly. + * @param fetchProperties properties of the associated bean that you want to include in the + * fetch (* means all properties, null also means all properties). + */ + Query fetchQuery(String path, String fetchProperties); + + /** + * Fetch the path and properties lazily (via batch lazy loading). + *

+ * This is the same as: + *

+ *
{@code
+   *
+   *  fetch(path, fetchProperties, new FetchConfig().lazy())
+   *
+   * }
+ *

+ * The reason for using fetchLazy() is to either: + *

+ *
    + *
  • Control/tune what is fetched as part of lazy loading
  • + *
  • Make use of the L2 cache, build this part of the graph from L2 cache
  • + *
+ * + * @param path the property path we wish to fetch lazily. + * @param fetchProperties properties of the associated bean that you want to include in the + * fetch (* means all properties, null also means all properties). + */ + Query fetchLazy(String path, String fetchProperties); + /** * Additionally specify a FetchConfig to use a separate query or lazy loading * to load this path. @@ -452,13 +499,17 @@ public interface Query { * .findList(); * * }
+ * + * @param path the property path we wish to fetch eagerly. */ - Query fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig); + Query fetch(String path, String fetchProperties, FetchConfig fetchConfig); /** - * Specify a path to load including all its properties. + * Specify a path to fetch eagerly including all its properties. *

- * The same as {@link #fetch(String, String)} with the fetchProperties as "*". + * Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can + * not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean + * will automatically convert this fetch query into a "query join" - i.e. use fetchQuery(). *

*
{@code
    *
@@ -471,10 +522,56 @@ public interface Query {
    *
    * }
* - * @param path the property of an associated (1-1,1-M,M-1,M-M) bean. + * @param path the property path we wish to fetch eagerly. */ Query fetch(String path); + /** + * Fetch the path eagerly using a "query join" (separate SQL query). + *

+ * This is the same as: + *

+ *
{@code
+   *
+   *  fetch(path, new FetchConfig().query())
+   *
+   * }
+ *

+ * This would be used instead of a fetch() when we use a separate SQL query to fetch this + * part of the object graph rather than a SQL join. + *

+ *

+ * We might typically get a performance benefit when the path to fetch is a OneToMany + * or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many + * is high. + *

+ * + * @param path the property path we wish to fetch eagerly + */ + Query fetchQuery(String path); + + /** + * Fetch the path lazily (via batch lazy loading). + *

+ * This is the same as: + *

+ *
{@code
+   *
+   *  fetch(path, new FetchConfig().lazy())
+   *
+   * }
+ *

+ * The reason for using fetchLazy() is to either: + *

+ *
    + *
  • Control/tune what is fetched as part of lazy loading
  • + *
  • Make use of the L2 cache, build this part of the graph from L2 cache
  • + *
+ * + * @param path the property path we wish to fetch lazily. + */ + Query fetchLazy(String path); + /** * Additionally specify a JoinConfig to specify a "query join" and or define * the lazy loading query. @@ -737,6 +834,7 @@ public interface Query { * Deprecated in favor of findCount(). *

* Return the count of entities this query should return. + * * @deprecated */ int findRowCount(); @@ -1199,6 +1297,16 @@ public interface Query { * Gives the JDBC driver a hint as to the number of rows that should be * fetched from the database when more rows are needed for ResultSet. *

+ *

+ * Note that internally findEach and findEachWhile will set the fetch size + * if it has not already as these queries expect to process a lot of rows. + * If we didn't then Postgres and MySql for example would eagerly pull back + * all the row data and potentially consume a lot of memory in the process. + *

+ *

+ * As findEach and findEachWhile automatically set the fetch size we don't have + * to do so generally but we might still wish to for tuning a specific use case. + *

*/ Query setBufferFetchSizeHint(int fetchSize); diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index dedc9f597..24bdea098 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -43,6 +43,10 @@ public class DefaultOrmQuery implements SpiQuery { public static final String DEFAULT_QUERY_NAME = "default"; + private static final FetchConfig FETCH_QUERY = new FetchConfig().query(); + + private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy(); + private final Class beanType; private final BeanDescriptor beanDescriptor; @@ -1013,6 +1017,16 @@ public class DefaultOrmQuery implements SpiQuery { return fetch(property, null, null); } + @Override + public Query fetchQuery(String property) { + return fetch(property, null, FETCH_QUERY); + } + + @Override + public Query fetchLazy(String property) { + return fetch(property, null, FETCH_LAZY); + } + @Override public DefaultOrmQuery fetch(String property, FetchConfig joinConfig) { return fetch(property, null, joinConfig); @@ -1023,6 +1037,16 @@ public class DefaultOrmQuery implements SpiQuery { return fetch(property, columns, null); } + @Override + public Query fetchQuery(String property, String columns) { + return fetch(property, columns, FETCH_QUERY); + } + + @Override + public Query fetchLazy(String property, String columns) { + return fetch(property, columns, FETCH_LAZY); + } + @Override public DefaultOrmQuery fetch(String property, String columns, FetchConfig config) { detail.fetch(property, columns, config); From 9d23c1d56e5774561ded8802cbdbfaed9e2095f1 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 23:30:26 +1200 Subject: [PATCH 36/65] #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use --- ...faultServer_createOrmQueryRequestTest.java | 28 ++++++++++ .../server/loadcontext/DLoadContextTest.java | 14 +++++ .../TestLazyLoadEmptyCollection.java | 6 ++- .../tests/batchload/TestSecondaryQueries.java | 52 +++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/avaje/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java b/src/test/java/com/avaje/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java index d61015f1e..d45ee0f5e 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/core/DefaultServer_createOrmQueryRequestTest.java @@ -153,6 +153,20 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase { assertThat(detail.getFetchPaths()).containsExactly("customer"); } + @Test + public void testJoinOrder_when_queryFetch_expect_getFetchPaths_doesNotIncludeQueryJoin_via_fetchQuery() { + + Query query = Ebean.find(Order.class) + .select("status, orderDate") + .fetch("customer", "name") + .fetchQuery("details"); + + OrmQueryRequest queryRequest = queryRequest(query); + OrmQueryDetail detail = queryRequest.getQuery().getDetail(); + + assertThat(detail.getFetchPaths()).containsExactly("customer"); + } + @Test public void testJoinOrder_when_lazyFetch_expect_getFetchPaths_doesNotIncludeQueryJoin() { @@ -167,6 +181,20 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase { assertThat(detail.getFetchPaths()).containsExactly("customer"); } + @Test + public void testJoinOrder_when_lazyFetch_expect_getFetchPaths_doesNotIncludeQueryJoin_via_fetchLazy() { + + Query query = Ebean.find(Order.class) + .select("status, orderDate") + .fetch("customer", "name") + .fetchLazy("details"); + + OrmQueryRequest queryRequest = queryRequest(query); + OrmQueryDetail detail = queryRequest.getQuery().getDetail(); + + assertThat(detail.getFetchPaths()).containsExactly("customer"); + } + @Test public void testJoinOrder_when_lazyFetchAndHasChildren_expect_getFetchPaths_doesNotIncludeJoinOrChild() { diff --git a/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java b/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java index e81c52d48..151d6a5da 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContextTest.java @@ -49,6 +49,20 @@ public class DLoadContextTest extends BaseTestCase { assertThat(customer.secondaryBatchSize).isEqualTo(100); } + @Test + public void construct_when_fetchQuery_expect_100_batchSize_viaFetchQuery() { + + OrmQueryRequest queryRequest = queryRequest(query().fetchQuery("customer")); + queryRequest.initTransIfRequired(); + queryRequest.endTransIfRequired(); + + DLoadContext graphContext = (DLoadContext)queryRequest.getGraphContext(); + DLoadBeanContext customer = graphContext.getBeanContext("customer"); + + assertThat(customer.firstBatchSize).isEqualTo(100); + assertThat(customer.secondaryBatchSize).isEqualTo(100); + } + @Test public void construct_when_fetchQuery50_expect_50_batchSize() { diff --git a/src/test/java/com/avaje/tests/batchload/TestLazyLoadEmptyCollection.java b/src/test/java/com/avaje/tests/batchload/TestLazyLoadEmptyCollection.java index 9e72be21a..6a5196c50 100644 --- a/src/test/java/com/avaje/tests/batchload/TestLazyLoadEmptyCollection.java +++ b/src/test/java/com/avaje/tests/batchload/TestLazyLoadEmptyCollection.java @@ -26,8 +26,10 @@ public class TestLazyLoadEmptyCollection extends BaseTestCase { Ebean.save(c); - List list = Ebean.find(Customer.class).fetch("contacts", new FetchConfig().query(0)) - .fetch("contacts.notes", new FetchConfig().query(100)).findList(); + List list = Ebean.find(Customer.class) + .fetch("contacts", new FetchConfig().query(0)) + .fetch("contacts.notes", new FetchConfig().query(100)) + .findList(); for (Customer customer : list) { List contacts = customer.getContacts(); diff --git a/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java b/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java index 577a290a3..b064bf73f 100644 --- a/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java +++ b/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java @@ -2,6 +2,7 @@ package com.avaje.tests.batchload; import java.util.List; +import org.avaje.ebeantest.LoggedSqlCollector; import org.junit.Assert; import org.junit.Test; @@ -14,8 +15,59 @@ import com.avaje.tests.model.basic.Customer; import com.avaje.tests.model.basic.Order; import com.avaje.tests.model.basic.ResetBasicData; +import static org.assertj.core.api.Assertions.assertThat; + public class TestSecondaryQueries extends BaseTestCase { + @Test + public void fetchQuery() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + Ebean.find(Order.class) + .select("status") + .fetchQuery("customer", "name") + .findList(); + + List sql = LoggedSqlCollector.stop(); + + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("select t0.id c0, t0.status c1, t0.kcustomer_id c2 from o_order t0"); + assertThat(sql.get(1)).contains("select t0.id c0, t0.name c1 from o_customer t0 where t0.id in"); + } + + @Test + public void fetchLazy() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List orders = Ebean.find(Order.class) + .select("status") + .fetchLazy("customer", "name") + .setMaxRows(10) + .findList(); + + List sql = LoggedSqlCollector.stop(); + + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("select t0.id c0, t0.status c1, t0.kcustomer_id c2 from o_order t0"); + + LoggedSqlCollector.start(); + + // invoke lazy loading + for (Order order : orders) { + order.getCustomer().getName(); + } + + sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("select t0.id c0, t0.name c1 from o_customer t0 where t0.id in"); + } + @Test public void testSecQueryOneToMany() { From d08ac6973e430b366799f32d72663ee5908a9fe1 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 23:33:02 +1200 Subject: [PATCH 37/65] #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use --- .../java/com/avaje/tests/batchload/TestSecondaryQueries.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java b/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java index b064bf73f..5651f484d 100644 --- a/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java +++ b/src/test/java/com/avaje/tests/batchload/TestSecondaryQueries.java @@ -49,6 +49,7 @@ public class TestSecondaryQueries extends BaseTestCase { .select("status") .fetchLazy("customer", "name") .setMaxRows(10) + .setUseCache(false) .findList(); List sql = LoggedSqlCollector.stop(); From 380660913f677efe774dfcedcd739d87b0b85198 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 2 Aug 2016 23:42:00 +1200 Subject: [PATCH 38/65] No effective change - javadoc update on Query --- src/main/java/com/avaje/ebean/Query.java | 94 ++++-------------------- 1 file changed, 16 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 3161ef96b..fc7ff5ba9 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -35,7 +35,6 @@ import java.util.Set; *
{@code
  *
  * String oql =
- *   	"  find  order "
  *   	+" fetch customer "
  *   	+" fetch details "
  *   	+" where customer.name like :custName and orderDate > :minOrderDate "
@@ -96,33 +95,24 @@ import java.util.Set;
  * Refer to "ALL Properties/Columns" mode of Optimistic Concurrency checking.
  * 

*
{@code
- * [ find  {bean type} [ ( * | {fetch properties} ) ] ]
- * [ fetch {associated bean} [ ( * | {fetch properties} ) ] ]
+ * [ select [ ( * | {fetch properties} ) ] ]
+ * [ fetch {path} [ ( * | {fetch properties} ) ] ]
  * [ where {predicates} ]
  * [ order by {order by properties} ]
  * [ limit {max rows} [ offset {first row} ] ]
  * }
*

- * FIND {bean type} [ ( * | {fetch properties} ) ] + * SELECT [ ( * | {fetch properties} ) ] *

*

- * With the find you specify the type of beans to fetch. You can optionally - * specify a list of properties to fetch. If you do not specify a list of - * properties ALL the properties for those beans are fetched. + * With the select you can specify a list of properties to fetch. *

*

- * In object graph terms the find clause specifies the type of bean at - * the root level and the fetch clauses specify the paths of the object - * graph to populate. - *

- *

- * FETCH {associated property} [ ( * | {fetch - * properties} ) ] + * FETCH {path} [ ( * | {fetch properties} ) ] *

*

* With the fetch you specify the associated property to fetch and populate. The - * associated property is a OneToOnem, ManyToOne, OneToMany or ManyToMany - * property. When the query is executed Ebean will fetch the associated data. + * path is a OneToOne, ManyToOne, OneToMany or ManyToMany property. *

*

* For fetch of a path we can optionally specify a list of properties to fetch. @@ -153,41 +143,33 @@ import java.util.Set; *

*

Examples of Ebean's Query Language

*

- * Find orders fetching all its properties - *

- *
{@code
- * find order
- * }
- *

- * Find orders fetching all its properties - *

- *
{@code
- * find order (*)
- * }
- *

* Find orders fetching its id, shipDate and status properties. Note that the id * property is always fetched even if it is not included in the list of fetch * properties. *

*
{@code
- * find order (shipDate, status)
+ *
+ * select (shipDate, status)
+ *
  * }
*

* Find orders with a named bind variable (that will need to be bound via * {@link Query#setParameter(String, Object)}). *

*
{@code
- * find order
+ *
  * where customer.name like :custLike
+ *
  * }
*

* Find orders and also fetch the customer with a named bind parameter. This * will fetch and populate both the order and customer objects. *

*
{@code
- * find  order
+ *
  * fetch customer
  * where customer.id = :custId
+ *
  * }
*

* Find orders and also fetch the customer, customer shippingAddress, order @@ -198,57 +180,13 @@ import java.util.Set; * populated. *

*
{@code
- * find  order
+ *
  * fetch customer (name)
  * fetch customer.shippingAddress
  * fetch details
  * fetch details.product (sku, name)
+ *
  * }
- *

Early parsing of the Query

- *

- * When you get a Query object from a named query, the query statement has - * already been parsed. You can then add to that query (add fetch paths, add to - * the where clause) or override some of its settings (override the order by - * clause, first rows, max rows). - *

- *

- * The thought is that you can use named queries as a 'starting point' and then - * modify the query to suit specific needs. - *

- *

Building the Where clause

- *

- * You can add to the where clause using Expression objects or a simple String. - * Note that the ExpressionList has methods to add most of the common - * expressions that you will need. - *

    - *
  • where(String addToWhereClause)
  • - *
  • where().add(Expression expression)
  • - *
  • where().eq(propertyName, value).like(propertyName , value)...
  • - *
- *

- *

- * The full WHERE clause is constructed by appending together - *

  • original query where clause (Named query or query.setQuery(String oql))
  • - *
  • clauses added via query.where(String addToWhereClause)
  • - *
  • clauses added by Expression objects
  • - *

    - *

    - * The above is the order that these are clauses are appended to give the full - * WHERE clause. - *

    - *

    Design Goal

    - *

    - * This query language is NOT designed to be a replacement for SQL. It is - * designed to be a simple way to describe the "Object Graph" you want Ebean to - * build for you. Each find/fetch represents a node in that "Object Graph" which - * makes it easy to define for each node which properties you want to fetch. - *

    - *

    - * Once you hit the limits of this language such as wanting aggregate functions - * (sum, average, min etc) or recursive queries etc you use SQL. Ebean's goal is - * to make it as easy as possible to use your own SQL to populate entity beans. - * Refer to {@link RawSql} . - *

    * * @param the type of Entity bean this query will fetch. */ @@ -304,7 +242,7 @@ public interface Query { * Specify the PersistenceContextScope to use for this query. *

    * When this is not set the 'default' configured on {@link com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)} - * is used - this value defaults to {@link com.avaje.ebean.PersistenceContextScope#TRANSACTION}. + * is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}. *

    * Note that the same persistence Context is used for subsequent lazy loading and query join queries. *

    From 5dc296e64403570983671ffa67ce956a84154ea5 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Wed, 3 Aug 2016 00:38:58 +1200 Subject: [PATCH 39/65] #798 - Add @Transactional based test --- .../batchinsert/TestBatchInsertFlush.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java b/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java index 141da0b3c..8cbd0f517 100644 --- a/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java +++ b/src/test/java/com/avaje/tests/batchinsert/TestBatchInsertFlush.java @@ -4,6 +4,7 @@ import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; import com.avaje.ebean.EbeanServer; import com.avaje.ebean.Transaction; +import com.avaje.ebean.annotation.Transactional; import com.avaje.ebean.config.PersistBatch; import com.avaje.tests.model.basic.EBasicVer; import org.junit.Test; @@ -14,6 +15,24 @@ import static org.junit.Assert.assertNotNull; public class TestBatchInsertFlush extends BaseTestCase { + @Test + @Transactional(batch = PersistBatch.ALL) + public void transactional_flushOnGetId() { + + EbeanServer server = Ebean.getDefaultServer(); + + EBasicVer b1 = new EBasicVer("b1"); + server.save(b1); + + EBasicVer b2 = new EBasicVer("b2"); + server.save(b2); + + Integer id = b1.getId(); + assertNotNull(id); + EBasicVer b3 = new EBasicVer("b3"); + server.save(b3); + } + @Test public void testFlushOnGetId() { From f42682ca9089aa18ab596515c4f7c7bbd625526e Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Wed, 3 Aug 2016 00:40:18 +1200 Subject: [PATCH 40/65] [maven-release-plugin] prepare release avaje-ebeanorm-8.1.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 08a05d616..e25af6ee1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 8.1.1-SNAPSHOT + 8.1.1 jar avaje-ebeanorm @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - HEAD + avaje-ebeanorm-8.1.1 From 9472592a50d4c935cb6f1da74423e57519c4a8cf Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Wed, 3 Aug 2016 00:40:37 +1200 Subject: [PATCH 41/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e25af6ee1..988feda11 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 8.1.1 + 8.1.2-SNAPSHOT jar avaje-ebeanorm @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - avaje-ebeanorm-8.1.1 + HEAD From 4ff10da739ecb1b7f4474d7dfdeb5d0fbf2d3ba7 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Wed, 3 Aug 2016 16:23:26 +1200 Subject: [PATCH 42/65] #801 - Change maven groupId ... to org.avaje.ebean, artifactId to ebean --- pom.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 988feda11..ccdee50eb 100644 --- a/pom.xml +++ b/pom.xml @@ -7,12 +7,12 @@ 1.1 - org.avaje.ebeanorm - avaje-ebeanorm - 8.1.2-SNAPSHOT + org.avaje.ebean + ebean + 8.1.1-SNAPSHOT jar - avaje-ebeanorm + ebean http://ebean-orm.github.io/ @@ -172,8 +172,8 @@ - org.avaje.ebeanorm - avaje-ebeanorm-agent + org.avaje.ebean + ebean-agent 8.1.1 test @@ -247,8 +247,8 @@ - org.avaje.ebeanorm - avaje-ebeanorm-mavenenhancer + org.avaje.ebean + ebean-maven-plugin 8.1.1 @@ -304,7 +304,7 @@ maven-javadoc-plugin 2.9.1 - Ebean 7 + Ebean 8 src/main/java/com/avaje/ebean/overview.html 1.8 org.avaje.doclet.PygmentsDoclet From 629fb7a433c65f75f571f7c5e9fa90669d63b5db Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Wed, 3 Aug 2016 16:24:23 +1200 Subject: [PATCH 43/65] [maven-release-plugin] prepare release ebean-8.1.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ccdee50eb..838815767 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebean ebean - 8.1.1-SNAPSHOT + 8.1.1 jar ebean @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - HEAD + ebean-8.1.1 From ea69cae4a311539e65367627ec94ee6fc2cf910f Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Wed, 3 Aug 2016 16:24:43 +1200 Subject: [PATCH 44/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 838815767..0d0e04146 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebean ebean - 8.1.1 + 8.1.2-SNAPSHOT jar ebean @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - ebean-8.1.1 + HEAD From 9a5cb242ce210ce05f71e4723851297f52378701 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 13:56:09 +1200 Subject: [PATCH 45/65] No effective change - remove commented out line from pom --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0d0e04146..78d4fb594 100644 --- a/pom.xml +++ b/pom.xml @@ -256,7 +256,6 @@ process-test-classes target/test-classes - debug=1 From 1be30f167100caad994b27408657734511c05fc7 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 16:41:50 +1200 Subject: [PATCH 46/65] #125 - ENH: Add support for query returning a List of single Attribute type --- .../java/com/avaje/ebean/EbeanServer.java | 34 +++ .../java/com/avaje/ebean/ExpressionList.java | 80 +++++-- src/main/java/com/avaje/ebean/Query.java | 32 +++ .../com/avaje/ebeaninternal/api/SpiQuery.java | 23 ++ .../server/core/DefaultServer.java | 17 ++ .../server/core/OrmQueryEngine.java | 8 + .../server/core/OrmQueryRequest.java | 8 + .../server/core/SpiOrmQueryRequest.java | 5 + .../expression/DefaultExpressionList.java | 5 + .../server/expression/JunctionExpression.java | 5 + .../server/query/CQueryBuilder.java | 31 ++- .../server/query/CQueryEngine.java | 24 +- .../server/query/CQueryFetchBase.java | 208 ++++++++++++++++++ .../server/query/CQueryFetchIds.java | 188 +--------------- .../query/CQueryFetchSingleAttribute.java | 71 ++++++ .../server/query/CQueryPlan.java | 3 + .../server/query/DefaultOrmQueryEngine.java | 6 + .../server/query/SqlTreeBuilder.java | 2 +- .../server/query/SqlTreeNode.java | 7 + .../server/query/SqlTreeNodeBean.java | 5 + .../server/query/SqlTreeNodeExtraJoin.java | 6 + .../query/SqlTreeNodeManyWhereJoin.java | 6 + .../server/querydefn/DefaultOrmQuery.java | 27 +++ .../ebeaninternal/api/TDSpiEbeanServer.java | 5 + .../query/other/TestQuerySingleAttribute.java | 128 +++++++++++ 25 files changed, 716 insertions(+), 218 deletions(-) create mode 100644 src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java create mode 100644 src/test/java/com/avaje/tests/query/other/TestQuerySingleAttribute.java diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index 93f1af715..2956b51ce 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -988,6 +988,40 @@ public interface EbeanServer { */ Map findMap(Query query, Transaction transaction); + /** + * Execute the query returning a list of values for a single property. + * + *

    Example 1:

    + *
    {@code
    +   *
    +   *  List names =
    +   *    Ebean.find(Customer.class)
    +   *      .select("name")
    +   *      .orderBy().asc("name")
    +   *      .findSingleAttributeList();
    +   *
    +   * }
    + * + *

    Example 2:

    + *
    {@code
    +   *
    +   *  List names =
    +   *    Ebean.find(Customer.class)
    +   *      .setDistinct(true)
    +   *      .select("name")
    +   *      .where().eq("status", Customer.Status.NEW)
    +   *      .orderBy().asc("name")
    +   *      .setMaxRows(100)
    +   *      .findSingleAttributeList();
    +   *
    +   * }
    + * + * @return the list of values for the selected property + * + * @see Query#findSingleAttributeList() + */ + List findSingleAttributeList(Query query, Transaction transaction); + /** * Execute the query returning at most one entity bean or null (if no matching * bean is found). diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index cd7cf962d..37a034d0b 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -31,7 +31,7 @@ import java.util.Set; * more methods than you would initially expect (the ones duplicated from * Query). *

    - * + * * @see Query#where() */ public interface ExpressionList { @@ -83,14 +83,14 @@ public interface ExpressionList { /** * Add an orderBy clause to the query. - * + * * @see Query#orderBy(String) */ Query orderBy(String orderBy); /** * Add an orderBy clause to the query. - * + * * @see Query#orderBy(String) */ Query setOrderBy(String orderBy); @@ -164,14 +164,14 @@ public interface ExpressionList { /** * Execute the query returning a list. - * + * * @see Query#findList() */ List findList(); /** * Execute the query returning the list of Id's. - * + * * @see Query#findIds() */ List findIds(); @@ -193,14 +193,14 @@ public interface ExpressionList { /** * Execute the query returning a set. - * + * * @see Query#findSet() */ Set findSet(); /** * Execute the query returning a map. - * + * * @see Query#findMap() */ Map findMap(); @@ -210,6 +210,38 @@ public interface ExpressionList { */ Map findMap(String keyProperty, Class keyType); + /** + * Execute the query returning a list of values for a single property. + * + *

    Example 1:

    + *
    {@code
    +   *
    +   *  List names =
    +   *    Ebean.find(Customer.class)
    +   *      .select("name")
    +   *      .orderBy().asc("name")
    +   *      .findSingleAttributeList();
    +   *
    +   * }
    + * + *

    Example 2:

    + *
    {@code
    +   *
    +   *  List names =
    +   *    Ebean.find(Customer.class)
    +   *      .setDistinct(true)
    +   *      .select("name")
    +   *      .where().eq("status", Customer.Status.NEW)
    +   *      .orderBy().asc("name")
    +   *      .setMaxRows(100)
    +   *      .findSingleAttributeList();
    +   *
    +   * }
    + * + * @return the list of values for the selected property + */ + List findSingleAttributeList(); + /** * Execute the query returning a single bean or null (if no matching * bean is found). @@ -232,7 +264,7 @@ public interface ExpressionList { * execution status (isDone etc) and get the value (with or without a * timeout). *

    - * + * * @return a Future object for the row count query */ FutureRowCount findFutureCount(); @@ -251,7 +283,7 @@ public interface ExpressionList { * execution status (isDone etc) and get the value (with or without a * timeout). *

    - * + * * @return a Future object for the list of Id's */ FutureIds findFutureIds(); @@ -263,7 +295,7 @@ public interface ExpressionList { * execution status (isDone etc) and get the value (with or without a * timeout). *

    - * + * * @return a Future object for the list result of the query */ FutureList findFutureList(); @@ -326,7 +358,7 @@ public interface ExpressionList { /** * Specify specific properties to fetch on the main/root bean (aka partial * object). - * + * * @see Query#select(String) */ Query select(String properties); @@ -351,28 +383,28 @@ public interface ExpressionList { /** * Set the first row to fetch. - * + * * @see Query#setFirstRow(int) */ Query setFirstRow(int firstRow); /** * Set the maximum number of rows to fetch. - * + * * @see Query#setMaxRows(int) */ Query setMaxRows(int maxRows); /** * Set the name of the property which values become the key of a map. - * + * * @see Query#setMapKey(String) */ Query setMapKey(String mapKey); /** * Set to true to use the query for executing this query. - * + * * @see Query#setUseCache(boolean) */ Query setUseCache(boolean useCache); @@ -633,7 +665,7 @@ public interface ExpressionList { * To get control over the options you can create an ExampleExpression and set * those options such as case insensitive etc. *

    - * + * *
    {@code
        *
        * // create an example bean and set the properties
    @@ -641,26 +673,26 @@ public interface ExpressionList {
        * Customer example = new Customer();
        * example.setName("Rob%");
        * example.setNotes("%something%");
    -   * 
    +   *
        * List<Customer> list = Ebean.find(Customer.class).where()
        *     // pass the bean into the where() clause
        *     .exampleLike(example)
        *     // you can add other expressions to the same query
        *     .gt("id", 2).findList();
    -   * 
    +   *
        * }
    - * + * * Similarly you can create an ExampleExpression - * + * *
    {@code
        *
        * Customer example = new Customer();
        * example.setName("Rob%");
        * example.setNotes("%something%");
    -   * 
    +   *
        * // create a ExampleExpression with more control
        * ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
    -   * 
    +   *
        * List list = Ebean.find(Customer.class).where().add(qbe).findList();
        *
        * }
    @@ -762,7 +794,7 @@ public interface ExpressionList { * Exists expression */ ExpressionList exists(Query subQuery); - + /** * Not exists expression */ @@ -789,7 +821,7 @@ public interface ExpressionList { * Expression where all the property names in the map are equal to the * corresponding value. *

    - * + * * @param propertyMap * a map keyed by property names. */ diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index fc7ff5ba9..3baee31d8 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -677,6 +677,38 @@ public interface Query { */ Map findMap(String keyProperty, Class keyType); + /** + * Execute the query returning a list of values for a single property. + * + *

    Example 1:

    + *
    {@code
    +   *
    +   *  List names =
    +   *    Ebean.find(Customer.class)
    +   *      .select("name")
    +   *      .orderBy().asc("name")
    +   *      .findSingleAttributeList();
    +   *
    +   * }
    + * + *

    Example 2:

    + *
    {@code
    +   *
    +   *  List names =
    +   *    Ebean.find(Customer.class)
    +   *      .setDistinct(true)
    +   *      .select("name")
    +   *      .where().eq("status", Customer.Status.NEW)
    +   *      .orderBy().asc("name")
    +   *      .setMaxRows(100)
    +   *      .findSingleAttributeList();
    +   *
    +   * }
    + * + * @return the list of values for the selected property + */ +
    List findSingleAttributeList(); + /** * Execute the query returning either a single bean or null (if no matching * bean is found). diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java index 6ca8ca878..7c9c10c62 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java @@ -78,6 +78,11 @@ public interface SpiQuery extends Query { */ ID_LIST, + /** + * Find single attribute. + */ + ATTRIBUTE, + /** * Find rowCount. */ @@ -341,6 +346,24 @@ public interface SpiQuery extends Query { */ void setSelectId(); + /** + * Mark the query as selecting a single attribute. + */ + void setSingleAttribute(); + + /** + * Return true if this is singleAttribute query. + */ + boolean isSingleAttribute(); + + /** + * Return true if the query should include the Id property. + *

    + * distinct and single attribute queries exclude the Id property. + *

    + */ + boolean isWithId(); + /** * Set a filter to a join path. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index 75f91947e..e6f062dcd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -1152,6 +1152,23 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Override + public
    List findSingleAttributeList(Query query, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.ATTRIBUTE, query, t); + Object result = request.getFromQueryCache(); + if (result != null) { + return (List) result; + } + try { + request.initTransIfRequired(); + return (List) request.findSingleAttributeList(); + + } finally { + request.endTransIfRequired(); + } + } + public int findCount(Query query, Transaction t) { SpiQuery copy = ((SpiQuery) query).copy(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java index 02464b5bc..a51b3a5b2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java @@ -21,6 +21,14 @@ public interface OrmQueryEngine { */ BeanCollection findMany(OrmQueryRequest request); + /** + * Execute the findSingleAttributeList query. + */ + List findSingleAttributeList(OrmQueryRequest request); + + /** + * Execute the findVersions query. + */ List> findVersions(OrmQueryRequest request); /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java index 0aa5a472b..e3d8a2126 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java @@ -373,6 +373,14 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe return (Map) queryEngine.findMany(this); } + /** + * Execute the findSingleAttributeList query. + */ + @Override + public List findSingleAttributeList() { + return queryEngine.findSingleAttributeList(this); + } + /** * Return a bean specific finder if one has been set. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java index b5f22603a..ae0013f1a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -107,6 +107,11 @@ public interface SpiOrmQueryRequest extends DocQueryRequest { */ Map findMap(); + /** + * Execute the findSingleAttributeList query. + */ + List findSingleAttributeList(); + /** * Try to get the query result from the query cache. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index 1d84c4029..83f1198b6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -388,6 +388,11 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findMap(keyProperty, keyType); } + @Override + public List findSingleAttributeList() { + return query.findSingleAttributeList(); + } + @Override public T findUnique() { return query.findUnique(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index e6bb77918..6db932350 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -400,6 +400,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.findMap(keyProperty, keyType); } + @Override + public List findSingleAttributeList() { + return exprList.findSingleAttributeList(); + } + @Override public PagedList findPagedList() { return exprList.findPagedList(); 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 846c06ffe..73036ac06 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java @@ -165,13 +165,35 @@ public class CQueryBuilder { return StringHelper.replaceString(sql, "${RTA}", replaceWith); } + public CQueryFetchSingleAttribute buildFetchAttributeQuery(OrmQueryRequest request) { + + SpiQuery query = request.getQuery(); + query.setSingleAttribute(); + + CQueryPredicates predicates = new CQueryPredicates(binder, request); + CQueryPlan queryPlan = request.getQueryPlan(); + if (queryPlan != null) { + predicates.prepare(false); + return new CQueryFetchSingleAttribute(request, predicates, queryPlan); + } + + // use RawSql or generated Sql + predicates.prepare(true); + + SqlTree sqlTree = createSqlTree(request, predicates, getHistorySupport(query), getDraftSupport(query)); + SqlLimitResponse s = buildSql(null, request, predicates, sqlTree); + + queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql()); + request.putQueryPlan(queryPlan); + return new CQueryFetchSingleAttribute(request, predicates, queryPlan); + } + /** * Build the row count query. */ public CQueryFetchIds buildFetchIdsQuery(OrmQueryRequest request) { SpiQuery query = request.getQuery(); - query.setSelectId(); CQueryPredicates predicates = new CQueryPredicates(binder, request); @@ -179,8 +201,7 @@ public class CQueryBuilder { if (queryPlan != null) { // skip building the SqlTree and Sql string predicates.prepare(false); - String sql = queryPlan.getSql(); - return new CQueryFetchIds(request, predicates, sql); + return new CQueryFetchIds(request, predicates, queryPlan.getSql()); } // use RawSql or generated Sql @@ -450,8 +471,8 @@ public class CQueryBuilder { } sb.append(select.getSelectSql()); - if (query.isDistinctQuery() && dbOrderBy != null) { - // add the orderby columns to the select clause (due to distinct) + if (query.isDistinctQuery() && dbOrderBy != null && !query.isSingleAttribute()) { + // add the orderBy columns to the select clause (due to distinct) sb.append(", ").append(convertDbOrderByForSelect(dbOrderBy)); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java index 0818ca8ca..bc105a514 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java @@ -88,6 +88,27 @@ public class CQueryEngine { } } + /** + * Build and execute the findSingleAttributeList query. + */ + public List findSingleAttributeList(OrmQueryRequest request) { + + CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request); + try { + List list = rcQuery.findList(); + if (request.isLogSql()) { + logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog()); + } + if (request.isLogSummary()) { + request.getTransaction().logSummary(rcQuery.getSummary()); + } + return list; + + } catch (SQLException e) { + throw CQuery.createPersistenceException(e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql()); + } + } + /** * Build and execute the find Id's query. */ @@ -97,15 +118,12 @@ public class CQueryEngine { try { BeanIdList list = rcQuery.findIds(); - if (request.isLogSql()) { logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog()); } - if (request.isLogSummary()) { request.getTransaction().logSummary(rcQuery.getSummary()); } - if (request.getQuery().isFutureFetch()) { // end the transaction for futureFindIds (it had it's own one) logger.debug("Future findIds completed!"); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java new file mode 100644 index 000000000..b25813bfc --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java @@ -0,0 +1,208 @@ +package com.avaje.ebeaninternal.server.query; + +import com.avaje.ebean.bean.BeanCollection; +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.bean.EntityBeanIntercept; +import com.avaje.ebean.bean.PersistenceContext; +import com.avaje.ebeaninternal.api.SpiQuery; +import com.avaje.ebeaninternal.api.SpiQuery.Mode; +import com.avaje.ebeaninternal.api.SpiTransaction; +import com.avaje.ebeaninternal.server.core.OrmQueryRequest; +import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; +import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import com.avaje.ebeaninternal.server.deploy.DbReadContext; +import com.avaje.ebeaninternal.server.type.DataReader; +import com.avaje.ebeaninternal.server.type.RsetDataReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +/** + * Base compiled query request for single attribute queries. + */ +public abstract class CQueryFetchBase { + + private static final Logger logger = LoggerFactory.getLogger(CQueryFetchBase.class); + + /** + * The overall find request wrapper object. + */ + protected final OrmQueryRequest request; + + protected final BeanDescriptor desc; + + protected final SpiQuery query; + + /** + * Where clause predicates. + */ + protected final CQueryPredicates predicates; + + /** + * The final sql that is generated. + */ + protected final String sql; + + protected RsetDataReader dataReader; + + /** + * The statement used to create the resultSet. + */ + protected PreparedStatement pstmt; + + protected String bindLog; + + protected int executionTimeMicros; + + protected int rowCount; + + protected final int maxRows; + + /** + * Create the Sql select based on the request. + */ + public CQueryFetchBase(OrmQueryRequest request, CQueryPredicates predicates, String sql) { + + this.request = request; + this.query = request.getQuery(); + this.sql = sql; + this.maxRows = query.getMaxRows(); + + query.setGeneratedSql(sql); + + this.desc = request.getBeanDescriptor(); + this.predicates = predicates; + } + + /** + * Return the bind log. + */ + public String getBindLog() { + return bindLog; + } + + /** + * Return the generated sql. + */ + public String getGeneratedSql() { + return sql; + } + + protected ResultSet prepareExecute() throws SQLException { + + SpiTransaction t = request.getTransaction(); + Connection conn = t.getInternalConnection(); + pstmt = conn.prepareStatement(sql); + + if (query.getBufferFetchSizeHint() > 0) { + pstmt.setFetchSize(query.getBufferFetchSizeHint()); + } + if (query.getTimeout() > 0) { + pstmt.setQueryTimeout(query.getTimeout()); + } + + bindLog = predicates.bind(pstmt, conn); + + ResultSet rset = pstmt.executeQuery(); + dataReader = new RsetDataReader(request.getDataTimeZone(), rset); + return rset; + } + + /** + * Close the resources. + *

    + * The jdbc resultSet and statement need to be closed. Its important that + * this method is called. + *

    + */ + protected void close() { + try { + if (dataReader != null) { + dataReader.close(); + dataReader = null; + } + } catch (SQLException e) { + logger.error("Error closing DataReader", e); + } + try { + if (pstmt != null) { + pstmt.close(); + pstmt = null; + } + } catch (SQLException e) { + logger.error("Error closing PreparedStatement", e); + } + } + + + protected class DbContext implements DbReadContext { + + public void propagateState(Object e) { + throw new RuntimeException("Not Called"); + } + + public Mode getQueryMode() { + return Mode.NORMAL; + } + + public DataReader getDataReader() { + return dataReader; + } + + public Boolean isReadOnly() { + return Boolean.FALSE; + } + + @Override + public boolean isDisableLazyLoading() { + return false; + } + + public boolean isRawSql() { + return false; + } + + public void register(String path, EntityBeanIntercept ebi) { + } + + public void register(String path, BeanCollection bc) { + } + + public BeanPropertyAssocMany getManyProperty() { + // always null + return null; + } + + public PersistenceContext getPersistenceContext() { + // always null + return null; + } + + public boolean isAutoTuneProfiling() { + return false; + } + + public void profileBean(EntityBeanIntercept ebi, String prefix) { + // no-op + } + + public void setCurrentPrefix(String currentPrefix, Map pathMap) { + // no-op + } + + public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) { + // no-op + } + + @Override + public boolean isDraftQuery() { + return false; + } + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java index 7000e6558..96ecbc8ef 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java @@ -1,86 +1,25 @@ package com.avaje.ebeaninternal.server.query; -import com.avaje.ebean.bean.BeanCollection; -import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebean.bean.EntityBeanIntercept; -import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebeaninternal.api.BeanIdList; -import com.avaje.ebeaninternal.api.SpiQuery; -import com.avaje.ebeaninternal.api.SpiQuery.Mode; -import com.avaje.ebeaninternal.api.SpiTransaction; import com.avaje.ebeaninternal.server.core.OrmQueryRequest; -import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; import com.avaje.ebeaninternal.server.deploy.DbReadContext; -import com.avaje.ebeaninternal.server.type.DataReader; -import com.avaje.ebeaninternal.server.type.RsetDataReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.sql.Connection; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; /** * Executes the select row count query. */ -public class CQueryFetchIds { - - private static final Logger logger = LoggerFactory.getLogger(CQueryFetchIds.class); - - /** - * The overall find request wrapper object. - */ - private final OrmQueryRequest request; - - private final BeanDescriptor desc; - - private final SpiQuery query; - - /** - * Where clause predicates. - */ - private final CQueryPredicates predicates; - - /** - * The final sql that is generated. - */ - private final String sql; - - private RsetDataReader dataReader; - - /** - * The statement used to create the resultSet. - */ - private PreparedStatement pstmt; - - private String bindLog; - - private int executionTimeMicros; - - private int rowCount; - - private final int maxRows; +public class CQueryFetchIds extends CQueryFetchBase { /** * Create the Sql select based on the request. */ public CQueryFetchIds(OrmQueryRequest request, CQueryPredicates predicates, String sql) { - - this.request = request; - this.query = request.getQuery(); - this.sql = sql; - this.maxRows = query.getMaxRows(); - - query.setGeneratedSql(sql); - - this.desc = request.getBeanDescriptor(); - this.predicates = predicates; + super(request, predicates, sql); } /** @@ -97,20 +36,6 @@ public class CQueryFetchIds { return sb.toString(); } - /** - * Return the bind log. - */ - public String getBindLog() { - return bindLog; - } - - /** - * Return the generated sql. - */ - public String getGeneratedSql() { - return sql; - } - /** * Execute the query returning the row count. */ @@ -131,22 +56,7 @@ public class CQueryFetchIds { BeanIdList result = new BeanIdList(idList); - SpiTransaction t = request.getTransaction(); - Connection conn = t.getInternalConnection(); - pstmt = conn.prepareStatement(sql); - - if (query.getBufferFetchSizeHint() > 0) { - pstmt.setFetchSize(query.getBufferFetchSizeHint()); - } - - if (query.getTimeout() > 0) { - pstmt.setQueryTimeout(query.getTimeout()); - } - - bindLog = predicates.bind(pstmt, conn); - - ResultSet rset = pstmt.executeQuery(); - dataReader = new RsetDataReader(request.getDataTimeZone(), rset); + ResultSet rset = prepareExecute(); boolean hitMaxRows = false; boolean hasMoreRows = false; @@ -183,96 +93,4 @@ public class CQueryFetchIds { } } - /** - * Close the resources. - *

    - * The jdbc resultSet and statement need to be closed. Its important that - * this method is called. - *

    - */ - private void close() { - try { - if (dataReader != null) { - dataReader.close(); - dataReader = null; - } - } catch (SQLException e) { - logger.error("Error closing DataReader", e); - } - try { - if (pstmt != null) { - pstmt.close(); - pstmt = null; - } - } catch (SQLException e) { - logger.error("Error closing PreparedStatement", e); - } - } - - - class DbContext implements DbReadContext { - - public void propagateState(Object e) { - throw new RuntimeException("Not Called"); - } - - public Mode getQueryMode() { - return Mode.NORMAL; - } - - public DataReader getDataReader() { - return dataReader; - } - - public Boolean isReadOnly() { - return Boolean.FALSE; - } - - @Override - public boolean isDisableLazyLoading() { - return false; - } - - public boolean isRawSql() { - return false; - } - - public void register(String path, EntityBeanIntercept ebi) { - } - - public void register(String path, BeanCollection bc) { - } - - public BeanPropertyAssocMany getManyProperty() { - // always null - return null; - } - - public PersistenceContext getPersistenceContext() { - // always null - return null; - } - - public boolean isAutoTuneProfiling() { - return false; - } - - public void profileBean(EntityBeanIntercept ebi, String prefix) { - // no-op - } - - public void setCurrentPrefix(String currentPrefix, Map pathMap) { - // no-op - } - - public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) { - // no-op - } - - @Override - public boolean isDraftQuery() { - return false; - } - } - } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java new file mode 100644 index 000000000..324c80cac --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java @@ -0,0 +1,71 @@ +package com.avaje.ebeaninternal.server.query; + +import com.avaje.ebeaninternal.server.core.OrmQueryRequest; +import com.avaje.ebeaninternal.server.deploy.BeanProperty; +import com.avaje.ebeaninternal.server.type.ScalarType; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Executes the select row count query. + */ +public class CQueryFetchSingleAttribute extends CQueryFetchBase { + + private final BeanProperty property; + + private final ScalarType scalarType; + + /** + * Create the Sql select based on the request. + */ + public CQueryFetchSingleAttribute(OrmQueryRequest request, CQueryPredicates predicates, CQueryPlan plan) { + super(request, predicates, plan.getSql()); + this.property = plan.getSingleProperty(); + this.scalarType = property.getScalarType(); + } + + /** + * Return a summary description of this query. + */ + public String getSummary() { + StringBuilder sb = new StringBuilder(80); + sb.append("FindAttr exeMicros[").append(executionTimeMicros) + .append("] rows[").append(rowCount) + .append("] type[").append(desc.getName()) + .append("] predicates[").append(predicates.getLogWhereSql()) + .append("] bind[").append(bindLog).append("]"); + + return sb.toString(); + } + + /** + * Execute the query returning the row count. + */ + public List findList() throws SQLException { + + long startNano = System.nanoTime(); + try { + + List result = new ArrayList(); + + ResultSet rset = prepareExecute(); + while (rset.next()) { + result.add(scalarType.read(dataReader)); + dataReader.resetColumnPosition(); + rowCount++; + } + + long exeNano = System.nanoTime() - startNano; + executionTimeMicros = (int) exeNano / 1000; + + return result; + + } finally { + close(); + } + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java index f4f831cef..6c490bf17 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java @@ -266,4 +266,7 @@ public class CQueryPlan { return stats.getLastQueryTime(); } + public BeanProperty getSingleProperty() { + return sqlTree.getRootNode().getSingleProperty(); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java index 3342637d4..963e72e93 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java @@ -71,6 +71,12 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine { return queryEngine.findIds(request); } + @Override + public List findSingleAttributeList(OrmQueryRequest request) { + flushJdbcBatchOnQuery(request); + return queryEngine.findSingleAttributeList(request); + } + public QueryIterator findIterate(OrmQueryRequest request) { // LIMITATION: You can not use QueryIterator to load bean cache diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java index aef2012fb..835fd97ed 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java @@ -260,7 +260,7 @@ public class SqlTreeBuilder { // Optional many property for lazy loading query BeanPropertyAssocMany lazyLoadMany = (query == null) ? null : query.getLazyLoadMany(); - boolean withId = !rawNoId && !subQuery && (query == null || !query.isDistinct()); + boolean withId = !rawNoId && !subQuery && (query == null || query.isWithId()); return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany, SpiQuery.TemporalMode.of(query), disableLazyLoad); } else if (prop instanceof BeanPropertyAssocMany) { 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 9aa8ac951..0313c351c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java @@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query; import com.avaje.ebean.Version; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebeaninternal.api.SpiQuery; +import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebeaninternal.server.deploy.DbReadContext; import com.avaje.ebeaninternal.server.deploy.DbSqlContext; @@ -62,4 +63,10 @@ public interface SqlTreeNode { * Return true if the query has a many join. */ boolean hasMany(); + + /** + * Return the property for singleAttribute query. + */ + BeanProperty getSingleProperty(); + } 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 29d7abe14..64e7894cc 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -137,6 +137,11 @@ public class SqlTreeNodeBean implements SqlTreeNode { pathMap = createPathMap(prefix, desc); } + @Override + public BeanProperty getSingleProperty() { + return properties[0]; + } + private Map createPathMap(String prefix, BeanDescriptor desc) { BeanPropertyAssocMany[] manys = desc.propertiesMany(); 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 ae5862267..2a7fd0cfb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java @@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query; import com.avaje.ebean.Version; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebeaninternal.api.SpiQuery; +import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; import com.avaje.ebeaninternal.server.deploy.DbReadContext; @@ -55,6 +56,11 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode { // nothing to do here } + @Override + public BeanProperty getSingleProperty() { + throw new IllegalStateException("No expected"); + } + /** * Return true if the extra join is a many join. *

    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 46c793428..b3c390761 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java @@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query; import com.avaje.ebean.Version; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebeaninternal.api.SpiQuery; +import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne; @@ -39,6 +40,11 @@ public class SqlTreeNodeManyWhereJoin implements SqlTreeNode { this.parentPrefix = split[0]; } + @Override + public BeanProperty getSingleProperty() { + throw new IllegalStateException("No expected"); + } + @Override public void addAsOfTableAlias(SpiQuery query) { // do nothing here ... diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 24bdea098..b3d3622db 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -192,6 +192,8 @@ public class DefaultOrmQuery implements SpiQuery { */ private boolean forUpdate; + private boolean singleAttribute; + /** * Set to true if this query has been tuned by autoTune. */ @@ -534,6 +536,26 @@ public class DefaultOrmQuery implements SpiQuery { select(beanDescriptor.getIdBinder().getIdProperty()); } + @Override + public void setSingleAttribute() { + this.singleAttribute = true; + } + + /** + * Return true if this is a single attribute query. + */ + public boolean isSingleAttribute() { + return singleAttribute; + } + + /** + * Return true if the Id should be included in the query. + */ + @Override + public boolean isWithId() { + return !distinct && !singleAttribute; + } + @Override public NaturalKeyBindParam getNaturalKeyBindParam() { NaturalKeyBindParam namedBind = null; @@ -1133,6 +1155,11 @@ public class DefaultOrmQuery implements SpiQuery { return (Map) findMap(); } + @Override + public List findSingleAttributeList() { + return (List)server.findSingleAttributeList(this, null); + } + @Override public T findUnique() { return server.findUnique(this, null); diff --git a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java index 345a4472f..030abb658 100644 --- a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java @@ -520,6 +520,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return null; } + @Override + public List findSingleAttributeList(Query query, Transaction transaction) { + return null; + } + @Override public T findUnique(Query query, Transaction transaction) { return null; diff --git a/src/test/java/com/avaje/tests/query/other/TestQuerySingleAttribute.java b/src/test/java/com/avaje/tests/query/other/TestQuerySingleAttribute.java new file mode 100644 index 000000000..7fddbceb3 --- /dev/null +++ b/src/test/java/com/avaje/tests/query/other/TestQuerySingleAttribute.java @@ -0,0 +1,128 @@ +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.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Test; + +import java.sql.Date; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestQuerySingleAttribute extends BaseTestCase { + + + @Test + public void exampleUsage() { + + ResetBasicData.reset(); + + List names = + Ebean.find(Customer.class) + .setDistinct(true) + .select("name") + .where().eq("status", Customer.Status.NEW) + .orderBy().asc("name") + .setMaxRows(100) + .findSingleAttributeList(); + + assertThat(names).isNotNull(); + } + + @Test + public void exampleUsage_otherType() { + + ResetBasicData.reset(); + + List dates = + Ebean.find(Customer.class) + .setDistinct(true) + .select("anniversary") + .where().isNotNull("anniversary") + .orderBy().asc("anniversary") + .findSingleAttributeList(); + + assertThat(dates).isNotNull(); + } + + @Test + public void withOrderBy() { + + Query query = + Ebean.find(Customer.class) + .setDistinct(true) + .select("name") + .where().eq("status", Customer.Status.NEW) + .orderBy().asc("name") + .setMaxRows(100); + + query.findSingleAttributeList(); + assertThat(query.getGeneratedSql()).contains("select distinct t0.name c0 from o_customer t0 where t0.status = ? order by t0.name "); + } + + @Test + public void basic() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Customer.class).select("name"); + + List names = query.findSingleAttributeList();//String.class); + + assertThat(query.getGeneratedSql()).contains("select t0.name c0 from o_customer t0"); + assertThat(names).isNotNull(); + } + + @Test + public void distinctAndWhere() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Customer.class) + .setDistinct(true) + .select("name") + .where().eq("status", Customer.Status.NEW) + .query(); + + List names = query.findSingleAttributeList(); + + assertThat(query.getGeneratedSql()).contains("select distinct t0.name c0 from o_customer t0 where t0.status = ? "); + assertThat(names).isNotNull(); + } + + @Test + public void distinctWhereWithJoin() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Customer.class) + .setDistinct(true) + .select("name") + .where().eq("status", Customer.Status.NEW) + .istartsWith("billingAddress.city", "auck") + .query(); + + List names = query.findSingleAttributeList(); + + assertThat(query.getGeneratedSql()).contains("select distinct t0.name c0 from o_customer t0 left outer join o_address t1 on t1.id = t0.billing_address_id where t0.status = ? and lower(t1.city) like ?"); + assertThat(names).isNotNull(); + } + + + @Test + public void queryPlan_expect_differentPlans() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Customer.class).select("name"); + query.findSingleAttributeList(); + assertThat(query.getGeneratedSql()).contains("select t0.name c0 from o_customer t0"); + + Query query2 = Ebean.find(Customer.class).select("name"); + query2.findList(); + assertThat(query2.getGeneratedSql()).contains("select t0.id c0, t0.name c1 from o_customer t0"); + } +} From 3c6eab6c85b19f1f6dbff62513560ca2f7a411ed Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 17:28:41 +1200 Subject: [PATCH 47/65] #802 - Find generics on findIds() - refactor internals of find ids to use find single attribute --- .../java/com/avaje/ebean/EbeanServer.java | 4 +- .../java/com/avaje/ebean/ExpressionList.java | 2 +- src/main/java/com/avaje/ebean/FutureIds.java | 14 -- src/main/java/com/avaje/ebean/Model.java | 2 +- src/main/java/com/avaje/ebean/Query.java | 2 +- .../ebeaninternal/api/SpiEbeanServer.java | 2 +- .../com/avaje/ebeaninternal/api/SpiQuery.java | 15 -- .../server/core/DefaultServer.java | 16 +- .../server/core/OrmQueryEngine.java | 2 +- .../server/core/OrmQueryRequest.java | 5 +- .../server/core/SpiOrmQueryRequest.java | 2 +- .../expression/DefaultExpressionList.java | 2 +- .../server/query/CQueryBuilder.java | 29 +-- .../server/query/CQueryEngine.java | 37 +--- .../server/query/CQueryFetchBase.java | 208 ------------------ .../server/query/CQueryFetchIds.java | 96 -------- .../query/CQueryFetchSingleAttribute.java | 125 ++++++++++- .../server/query/DefaultOrmQueryEngine.java | 2 +- .../server/query/QueryFutureIds.java | 10 +- .../server/querydefn/DefaultOrmQuery.java | 12 - .../ebeaninternal/api/TDSpiEbeanServer.java | 4 +- .../com/avaje/tests/basic/TestFetchId.java | 23 +- .../query/TestQueryPlanCacheRowCount.java | 6 +- .../other/TestFindIdsWithInheritance.java | 3 +- .../TestObjectGraphNodeStatsCollection.java | 2 +- 25 files changed, 162 insertions(+), 463 deletions(-) delete mode 100644 src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java delete mode 100644 src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index 2956b51ce..f4710e709 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -757,9 +757,9 @@ public interface EbeanServer { /** * Return the Id values of the query as a List. * - * @see com.avaje.ebean.Query#findIds() + * @see Query#findIds() */ - List findIds(Query query, Transaction transaction); + List findIds(Query query, Transaction transaction); /** * Execute the query visiting the each bean one at a time. diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index 37a034d0b..c0c8f6512 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -174,7 +174,7 @@ public interface ExpressionList { * * @see Query#findIds() */ - List findIds(); + List findIds(); /** * Return the count of entities this query should return. diff --git a/src/main/java/com/avaje/ebean/FutureIds.java b/src/main/java/com/avaje/ebean/FutureIds.java index ab8d80a5d..fb280b349 100644 --- a/src/main/java/com/avaje/ebean/FutureIds.java +++ b/src/main/java/com/avaje/ebean/FutureIds.java @@ -9,8 +9,6 @@ import java.util.concurrent.Future; * It extends the java.util.concurrent.Future with the ability to get the Id's * while the query is still executing in the background. *

    - * - * @author rbygrave */ public interface FutureIds extends Future> { @@ -19,16 +17,4 @@ public interface FutureIds extends Future> { */ Query getQuery(); - /** - * Return the list of Id's which could be partially populated. - *

    - * That is the query getting the id's could still be running and adding id's - * to this list. - *

    - *

    - * To get the list of Id's ensuring the query has finished use the - * {@link Future#get()} method instead of this one. - *

    - */ - List getPartialIds(); } diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java index edf0572e1..3f0bf9606 100644 --- a/src/main/java/com/avaje/ebean/Model.java +++ b/src/main/java/com/avaje/ebean/Model.java @@ -598,7 +598,7 @@ public abstract class Model { *

    * Equivalent to {@link Query#findIds()} */ - public List findIds() { + public List findIds() { return query().findIds(); } diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 3baee31d8..7fb526336 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -542,7 +542,7 @@ public interface Query { * * @see EbeanServer#findIds(Query, Transaction) */ - List findIds(); + List findIds(); /** * Execute the query processing the beans one at a time. diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiEbeanServer.java b/src/main/java/com/avaje/ebeaninternal/api/SpiEbeanServer.java index 42b56053c..cc98af802 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiEbeanServer.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiEbeanServer.java @@ -145,7 +145,7 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL * the query has finished (if executing in a background thread). *

    */ - List findIdsWithCopy(Query query, Transaction t); + List findIdsWithCopy(Query query, Transaction t); /** * Execute the findRowCount query but without copying the query. diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java index 7c9c10c62..b0254617b 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java @@ -251,21 +251,6 @@ public interface SpiQuery extends Query { List getSoftDeletePredicates(); - /** - * Set the list of Id's that is being populated. - *

    - * This is a mutating list of id's and we are setting this so that other - * threads have access to the id's before the id query has finished. - *

    - */ - void setIdList(List ids); - - /** - * Return the list of Id's that is currently being fetched by a background - * thread. - */ - List getIdList(); - /** * Return a copy of the query. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index e6f062dcd..7b2af928f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -1191,16 +1191,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } - public List findIds(Query query, Transaction t) { + public List findIds(Query query, Transaction t) { - SpiQuery copy = ((SpiQuery) query).copy(); - - return findIdsWithCopy(copy, t); + return findIdsWithCopy(((SpiQuery) query).copy(), t); } - public List findIdsWithCopy(Query query, Transaction t) { + public List findIdsWithCopy(Query query, Transaction t) { - SpiOrmQueryRequest request = createQueryRequest(Type.ID_LIST, query, t); + SpiOrmQueryRequest request = createQueryRequest(Type.ID_LIST, query, t); try { request.initTransIfRequired(); return request.findIds(); @@ -1258,12 +1256,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { SpiQuery copy = ((SpiQuery) query).copy(); copy.setFutureFetch(true); - // this is the list we will put the id's in ... create it now so - // it is available for other threads to read while the id query - // is still executing (we don't need to wait for it to finish) - List idList = Collections.synchronizedList(new ArrayList()); - copy.setIdList(idList); - Transaction newTxn = createTransaction(); CallableQueryIds call = new CallableQueryIds(this, copy, newTxn); diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java index a51b3a5b2..c38ce79ca 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java @@ -44,7 +44,7 @@ public interface OrmQueryEngine { /** * Execute the find id's query. */ - BeanIdList findIds(OrmQueryRequest request); + List findIds(OrmQueryRequest request); /** * Execute the query as a delete statement. diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java index e3d8a2126..c9bf91f82 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java @@ -304,9 +304,8 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe return queryEngine.findRowCount(this); } - public List findIds() { - BeanIdList idList = queryEngine.findIds(this); - return idList.getIdList(); + public List findIds() { + return queryEngine.findIds(this); } public void findEach(QueryEachConsumer consumer) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java index ae0013f1a..b7ed67df4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -70,7 +70,7 @@ public interface SpiOrmQueryRequest extends DocQueryRequest { /** * Execute the find ids query. */ - List findIds(); + List findIds(); /** * Execute the find returning a QueryIterator and visitor pattern. diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index 83f1198b6..a1e97986c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -354,7 +354,7 @@ public class DefaultExpressionList implements SpiExpressionList { } @Override - public List findIds() { + public List findIds() { return query.findIds(); } 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 73036ac06..ce8efe1fa 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java @@ -189,33 +189,12 @@ public class CQueryBuilder { } /** - * Build the row count query. + * Build the find ids query. */ - public CQueryFetchIds buildFetchIdsQuery(OrmQueryRequest request) { + public CQueryFetchSingleAttribute buildFetchIdsQuery(OrmQueryRequest request) { - SpiQuery query = request.getQuery(); - query.setSelectId(); - - CQueryPredicates predicates = new CQueryPredicates(binder, request); - CQueryPlan queryPlan = request.getQueryPlan(); - if (queryPlan != null) { - // skip building the SqlTree and Sql string - predicates.prepare(false); - return new CQueryFetchIds(request, predicates, queryPlan.getSql()); - } - - // use RawSql or generated Sql - predicates.prepare(true); - - SqlTree sqlTree = createSqlTree(request, predicates, getHistorySupport(query), getDraftSupport(query)); - SqlLimitResponse s = buildSql(null, request, predicates, sqlTree); - String sql = s.getSql(); - - // cache the query plan - queryPlan = new CQueryPlan(request, sql, sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql()); - - request.putQueryPlan(queryPlan); - return new CQueryFetchIds(request, predicates, sql); + request.getQuery().setSelectId(); + return buildFetchAttributeQuery(request); } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java index bc105a514..bcf3d5da5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java @@ -1,17 +1,16 @@ package com.avaje.ebeaninternal.server.query; -import com.avaje.ebean.config.ServerConfig; -import com.avaje.ebeaninternal.server.core.QueryIterator; import com.avaje.ebean.ValuePair; import com.avaje.ebean.Version; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.bean.ObjectGraphNode; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.DatabasePlatform; -import com.avaje.ebeaninternal.api.BeanIdList; import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeaninternal.server.core.DiffHelp; import com.avaje.ebeaninternal.server.core.OrmQueryRequest; +import com.avaje.ebeaninternal.server.core.QueryIterator; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.lib.util.Str; import com.avaje.ebeaninternal.server.persist.Binder; @@ -94,8 +93,13 @@ public class CQueryEngine { public List findSingleAttributeList(OrmQueryRequest request) { CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request); + return findAttributeList(request, rcQuery); + } + + @SuppressWarnings("unchecked") + private List findAttributeList(OrmQueryRequest request, CQueryFetchSingleAttribute rcQuery) { try { - List list = rcQuery.findList(); + List list = (List)rcQuery.findList(); if (request.isLogSql()) { logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog()); } @@ -112,29 +116,10 @@ public class CQueryEngine { /** * Build and execute the find Id's query. */ - public BeanIdList findIds(OrmQueryRequest request) { + public List findIds(OrmQueryRequest request) { - CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request); - try { - - BeanIdList list = rcQuery.findIds(); - if (request.isLogSql()) { - logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog()); - } - if (request.isLogSummary()) { - request.getTransaction().logSummary(rcQuery.getSummary()); - } - if (request.getQuery().isFutureFetch()) { - // end the transaction for futureFindIds (it had it's own one) - logger.debug("Future findIds completed!"); - request.getTransaction().end(); - } - - return list; - - } catch (SQLException e) { - throw CQuery.createPersistenceException(e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql()); - } + CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchIdsQuery(request); + return findAttributeList(request, rcQuery); } private void logGeneratedSql(OrmQueryRequest request, String sql, String bindLog) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java deleted file mode 100644 index b25813bfc..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchBase.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.avaje.ebeaninternal.server.query; - -import com.avaje.ebean.bean.BeanCollection; -import com.avaje.ebean.bean.EntityBean; -import com.avaje.ebean.bean.EntityBeanIntercept; -import com.avaje.ebean.bean.PersistenceContext; -import com.avaje.ebeaninternal.api.SpiQuery; -import com.avaje.ebeaninternal.api.SpiQuery.Mode; -import com.avaje.ebeaninternal.api.SpiTransaction; -import com.avaje.ebeaninternal.server.core.OrmQueryRequest; -import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; -import com.avaje.ebeaninternal.server.deploy.DbReadContext; -import com.avaje.ebeaninternal.server.type.DataReader; -import com.avaje.ebeaninternal.server.type.RsetDataReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Map; - -/** - * Base compiled query request for single attribute queries. - */ -public abstract class CQueryFetchBase { - - private static final Logger logger = LoggerFactory.getLogger(CQueryFetchBase.class); - - /** - * The overall find request wrapper object. - */ - protected final OrmQueryRequest request; - - protected final BeanDescriptor desc; - - protected final SpiQuery query; - - /** - * Where clause predicates. - */ - protected final CQueryPredicates predicates; - - /** - * The final sql that is generated. - */ - protected final String sql; - - protected RsetDataReader dataReader; - - /** - * The statement used to create the resultSet. - */ - protected PreparedStatement pstmt; - - protected String bindLog; - - protected int executionTimeMicros; - - protected int rowCount; - - protected final int maxRows; - - /** - * Create the Sql select based on the request. - */ - public CQueryFetchBase(OrmQueryRequest request, CQueryPredicates predicates, String sql) { - - this.request = request; - this.query = request.getQuery(); - this.sql = sql; - this.maxRows = query.getMaxRows(); - - query.setGeneratedSql(sql); - - this.desc = request.getBeanDescriptor(); - this.predicates = predicates; - } - - /** - * Return the bind log. - */ - public String getBindLog() { - return bindLog; - } - - /** - * Return the generated sql. - */ - public String getGeneratedSql() { - return sql; - } - - protected ResultSet prepareExecute() throws SQLException { - - SpiTransaction t = request.getTransaction(); - Connection conn = t.getInternalConnection(); - pstmt = conn.prepareStatement(sql); - - if (query.getBufferFetchSizeHint() > 0) { - pstmt.setFetchSize(query.getBufferFetchSizeHint()); - } - if (query.getTimeout() > 0) { - pstmt.setQueryTimeout(query.getTimeout()); - } - - bindLog = predicates.bind(pstmt, conn); - - ResultSet rset = pstmt.executeQuery(); - dataReader = new RsetDataReader(request.getDataTimeZone(), rset); - return rset; - } - - /** - * Close the resources. - *

    - * The jdbc resultSet and statement need to be closed. Its important that - * this method is called. - *

    - */ - protected void close() { - try { - if (dataReader != null) { - dataReader.close(); - dataReader = null; - } - } catch (SQLException e) { - logger.error("Error closing DataReader", e); - } - try { - if (pstmt != null) { - pstmt.close(); - pstmt = null; - } - } catch (SQLException e) { - logger.error("Error closing PreparedStatement", e); - } - } - - - protected class DbContext implements DbReadContext { - - public void propagateState(Object e) { - throw new RuntimeException("Not Called"); - } - - public Mode getQueryMode() { - return Mode.NORMAL; - } - - public DataReader getDataReader() { - return dataReader; - } - - public Boolean isReadOnly() { - return Boolean.FALSE; - } - - @Override - public boolean isDisableLazyLoading() { - return false; - } - - public boolean isRawSql() { - return false; - } - - public void register(String path, EntityBeanIntercept ebi) { - } - - public void register(String path, BeanCollection bc) { - } - - public BeanPropertyAssocMany getManyProperty() { - // always null - return null; - } - - public PersistenceContext getPersistenceContext() { - // always null - return null; - } - - public boolean isAutoTuneProfiling() { - return false; - } - - public void profileBean(EntityBeanIntercept ebi, String prefix) { - // no-op - } - - public void setCurrentPrefix(String currentPrefix, Map pathMap) { - // no-op - } - - public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) { - // no-op - } - - @Override - public boolean isDraftQuery() { - return false; - } - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java deleted file mode 100644 index 96ecbc8ef..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.avaje.ebeaninternal.server.query; - -import com.avaje.ebeaninternal.api.BeanIdList; -import com.avaje.ebeaninternal.server.core.OrmQueryRequest; -import com.avaje.ebeaninternal.server.deploy.DbReadContext; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Executes the select row count query. - */ -public class CQueryFetchIds extends CQueryFetchBase { - - /** - * Create the Sql select based on the request. - */ - public CQueryFetchIds(OrmQueryRequest request, CQueryPredicates predicates, String sql) { - super(request, predicates, sql); - } - - /** - * Return a summary description of this query. - */ - public String getSummary() { - StringBuilder sb = new StringBuilder(80); - sb.append("FindIds exeMicros[").append(executionTimeMicros) - .append("] rows[").append(rowCount) - .append("] type[").append(desc.getName()) - .append("] predicates[").append(predicates.getLogWhereSql()) - .append("] bind[").append(bindLog).append("]"); - - return sb.toString(); - } - - /** - * Execute the query returning the row count. - */ - public BeanIdList findIds() throws SQLException { - - long startNano = System.nanoTime(); - - try { - // get the list that we are going to put the id's into. - // This was already set so that it is available to be - // read by other threads (it is a synchronised list) - List idList = query.getIdList(); - if (idList == null) { - // running in foreground thread (not FutureIds query) - idList = Collections.synchronizedList(new ArrayList()); - query.setIdList(idList); - } - - BeanIdList result = new BeanIdList(idList); - - ResultSet rset = prepareExecute(); - - boolean hitMaxRows = false; - boolean hasMoreRows = false; - rowCount = 0; - - DbReadContext ctx = new DbContext(); - - while (rset.next()) { - Object idValue = desc.getIdBinder().read(ctx); - idList.add(idValue); - // reset back to 0 - dataReader.resetColumnPosition(); - rowCount++; - - if (maxRows > 0 && rowCount == maxRows) { - hitMaxRows = true; - hasMoreRows = rset.next(); - break; - - } - } - - if (hitMaxRows) { - result.setHasMore(hasMoreRows); - } - - long exeNano = System.nanoTime() - startNano; - executionTimeMicros = (int) exeNano / 1000; - - return result; - - } finally { - close(); - } - } - -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java index 324c80cac..431d84edd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchSingleAttribute.java @@ -1,20 +1,58 @@ package com.avaje.ebeaninternal.server.query; +import com.avaje.ebeaninternal.api.SpiQuery; +import com.avaje.ebeaninternal.api.SpiTransaction; import com.avaje.ebeaninternal.server.core.OrmQueryRequest; -import com.avaje.ebeaninternal.server.deploy.BeanProperty; +import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; +import com.avaje.ebeaninternal.server.type.RsetDataReader; import com.avaje.ebeaninternal.server.type.ScalarType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.sql.ResultSet; +import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** - * Executes the select row count query. + * Base compiled query request for single attribute queries. */ -public class CQueryFetchSingleAttribute extends CQueryFetchBase { +class CQueryFetchSingleAttribute { - private final BeanProperty property; + private static final Logger logger = LoggerFactory.getLogger(CQueryFetchSingleAttribute.class); + + /** + * The overall find request wrapper object. + */ + private final OrmQueryRequest request; + + private final BeanDescriptor desc; + + private final SpiQuery query; + + /** + * Where clause predicates. + */ + private final CQueryPredicates predicates; + + /** + * The final sql that is generated. + */ + private final String sql; + + private RsetDataReader dataReader; + + /** + * The statement used to create the resultSet. + */ + private PreparedStatement pstmt; + + private String bindLog; + + private int executionTimeMicros; + + private int rowCount; private final ScalarType scalarType; @@ -22,15 +60,20 @@ public class CQueryFetchSingleAttribute extends CQueryFetchBase { * Create the Sql select based on the request. */ public CQueryFetchSingleAttribute(OrmQueryRequest request, CQueryPredicates predicates, CQueryPlan plan) { - super(request, predicates, plan.getSql()); - this.property = plan.getSingleProperty(); - this.scalarType = property.getScalarType(); + this.request = request; + this.query = request.getQuery(); + this.sql = plan.getSql(); + this.desc = request.getBeanDescriptor(); + this.predicates = predicates; + this.scalarType = plan.getSingleProperty().getScalarType(); + + query.setGeneratedSql(sql); } /** * Return a summary description of this query. */ - public String getSummary() { + protected String getSummary() { StringBuilder sb = new StringBuilder(80); sb.append("FindAttr exeMicros[").append(executionTimeMicros) .append("] rows[").append(rowCount) @@ -44,15 +87,16 @@ public class CQueryFetchSingleAttribute extends CQueryFetchBase { /** * Execute the query returning the row count. */ - public List findList() throws SQLException { + protected List findList() throws SQLException { long startNano = System.nanoTime(); try { + prepareExecute(); + List result = new ArrayList(); - ResultSet rset = prepareExecute(); - while (rset.next()) { + while (dataReader.next()) { result.add(scalarType.read(dataReader)); dataReader.resetColumnPosition(); rowCount++; @@ -68,4 +112,61 @@ public class CQueryFetchSingleAttribute extends CQueryFetchBase { } } + /** + * Return the bind log. + */ + protected String getBindLog() { + return bindLog; + } + + /** + * Return the generated sql. + */ + protected String getGeneratedSql() { + return sql; + } + + private void prepareExecute() throws SQLException { + + SpiTransaction t = request.getTransaction(); + Connection conn = t.getInternalConnection(); + pstmt = conn.prepareStatement(sql); + + if (query.getBufferFetchSizeHint() > 0) { + pstmt.setFetchSize(query.getBufferFetchSizeHint()); + } + if (query.getTimeout() > 0) { + pstmt.setQueryTimeout(query.getTimeout()); + } + + bindLog = predicates.bind(pstmt, conn); + dataReader = new RsetDataReader(request.getDataTimeZone(), pstmt.executeQuery()); + } + + /** + * Close the resources. + *

    + * The jdbc resultSet and statement need to be closed. Its important that + * this method is called. + *

    + */ + private void close() { + try { + if (dataReader != null) { + dataReader.close(); + dataReader = null; + } + } catch (SQLException e) { + logger.error("Error closing DataReader", e); + } + try { + if (pstmt != null) { + pstmt.close(); + pstmt = null; + } + } catch (SQLException e) { + logger.error("Error closing PreparedStatement", e); + } + } + } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java index 963e72e93..5a0a0112b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java @@ -65,7 +65,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine { return queryEngine.findRowCount(request); } - public BeanIdList findIds(OrmQueryRequest request) { + public List findIds(OrmQueryRequest request) { flushJdbcBatchOnQuery(request); return queryEngine.findIds(request); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/QueryFutureIds.java b/src/main/java/com/avaje/ebeaninternal/server/query/QueryFutureIds.java index 85ff80907..bf0d595cf 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/QueryFutureIds.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/QueryFutureIds.java @@ -1,12 +1,12 @@ package com.avaje.ebeaninternal.server.query; -import java.util.List; -import java.util.concurrent.FutureTask; - import com.avaje.ebean.FutureIds; import com.avaje.ebean.Query; import com.avaje.ebean.Transaction; +import java.util.List; +import java.util.concurrent.FutureTask; + /** * Default implementation of FutureIds. */ @@ -31,10 +31,6 @@ public class QueryFutureIds extends BaseFuture> implements Futur return call.query; } - public List getPartialIds() { - return call.query.getIdList(); - } - public boolean cancel(boolean mayInterruptIfRunning) { call.query.cancel(); return super.cancel(mayInterruptIfRunning); diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index b3d3622db..179999d93 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -123,8 +123,6 @@ public class DefaultOrmQuery implements SpiQuery { */ private ReadEvent futureFetchAudit; - private List partialIds; - private int timeout; /** @@ -1509,16 +1507,6 @@ public class DefaultOrmQuery implements SpiQuery { return disableReadAudit; } - @Override - public List getIdList() { - return partialIds; - } - - @Override - public void setIdList(List partialIds) { - this.partialIds = partialIds; - } - @Override public boolean isFutureFetch() { return futureFetch; diff --git a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java index 030abb658..be387934e 100644 --- a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java @@ -186,7 +186,7 @@ public class TDSpiEbeanServer implements SpiEbeanServer { } @Override - public List findIdsWithCopy(Query query, Transaction t) { + public List findIdsWithCopy(Query query, Transaction t) { return null; } @@ -466,7 +466,7 @@ public class TDSpiEbeanServer implements SpiEbeanServer { } @Override - public List findIds(Query query, Transaction transaction) { + public List findIds(Query query, Transaction transaction) { return null; } diff --git a/src/test/java/com/avaje/tests/basic/TestFetchId.java b/src/test/java/com/avaje/tests/basic/TestFetchId.java index 06b046972..2e0908bfb 100644 --- a/src/test/java/com/avaje/tests/basic/TestFetchId.java +++ b/src/test/java/com/avaje/tests/basic/TestFetchId.java @@ -1,17 +1,17 @@ package com.avaje.tests.basic; -import java.util.List; -import java.util.concurrent.ExecutionException; - -import org.junit.Assert; -import org.junit.Test; - import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; import com.avaje.ebean.FutureIds; import com.avaje.ebean.Query; import com.avaje.tests.model.basic.Order; import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Test; + +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; public class TestFetchId extends BaseTestCase { @@ -28,19 +28,12 @@ public class TestFetchId extends BaseTestCase { .query(); List ids = Ebean.getServer(null).findIds(query, null); + assertThat(ids).isNotEmpty(); FutureIds futureIds = Ebean.getServer(null).findFutureIds(query,null); - // this list is likely empty at this point and - // will get populated in the background - List partial = futureIds.getPartialIds(); - - // this is likely 0 or a small number - // wait for all the id's to be fetched List idList = futureIds.get(); - Assert.assertTrue("same instance", partial == idList); - - Assert.assertTrue("sz > 0", !ids.isEmpty()); + assertThat(idList).isNotEmpty(); } } diff --git a/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java b/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java index b31f33fe5..475fc4cfc 100644 --- a/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java +++ b/src/test/java/com/avaje/tests/query/TestQueryPlanCacheRowCount.java @@ -23,7 +23,7 @@ public class TestQueryPlanCacheRowCount extends BaseTestCase { int rc0 = query.findRowCount(); - List ids = query.findIds(); + List ids = query.findIds(); Assert.assertEquals(rc0, ids.size()); List list0 = query.findList(); @@ -32,7 +32,7 @@ public class TestQueryPlanCacheRowCount extends BaseTestCase { int rc1 = query.findCount(); Assert.assertEquals(rc0, rc1); - List ids1 = query.findIds(); + List ids1 = query.findIds(); Assert.assertEquals(rc0, ids1.size()); List list1 = query.findList(); @@ -53,7 +53,7 @@ public class TestQueryPlanCacheRowCount extends BaseTestCase { System.out.println("Expection Not same " + rc0 + " != " + rc2); Assert.assertNotSame(rc0, rc2); - List ids2 = query2.findIds(); + List ids2 = query2.findIds(); Assert.assertEquals(rc2, ids2.size()); List list2 = query2.findList(); diff --git a/src/test/java/com/avaje/tests/query/other/TestFindIdsWithInheritance.java b/src/test/java/com/avaje/tests/query/other/TestFindIdsWithInheritance.java index 511456106..fb65a46ee 100644 --- a/src/test/java/com/avaje/tests/query/other/TestFindIdsWithInheritance.java +++ b/src/test/java/com/avaje/tests/query/other/TestFindIdsWithInheritance.java @@ -20,8 +20,7 @@ public class TestFindIdsWithInheritance extends BaseTestCase { Ebean.save(truck); - List ids = Ebean.find(Vehicle.class).findIds(); - + List ids = Ebean.find(Vehicle.class).findIds(); Assert.assertNotNull(ids); Ebean.delete(truck); diff --git a/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java b/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java index 744559b44..9decc1dff 100644 --- a/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java +++ b/src/test/java/com/avaje/tests/query/other/TestObjectGraphNodeStatsCollection.java @@ -95,7 +95,7 @@ public class TestObjectGraphNodeStatsCollection extends BaseTestCase { ResetBasicData.reset(); - List ids = Ebean.find(Order.class).findIds(); + List ids = Ebean.find(Order.class).findIds(); Assert.assertTrue(!ids.isEmpty()); } From b5b221ffb1f8aea12facb024d87f941664a9f5b7 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 17:32:18 +1200 Subject: [PATCH 48/65] No effective change - remove unused constructors --- .../avaje/ebeaninternal/server/query/SqlTreeNodeBean.java | 7 ------- .../avaje/ebeaninternal/server/query/SqlTreeNodeRoot.java | 8 -------- 2 files changed, 15 deletions(-) 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 64e7894cc..c0ac1e85d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -83,13 +83,6 @@ public class SqlTreeNodeBean implements SqlTreeNode { */ private boolean intersectionAsOfTableAlias; - /** - * Construct for Raw SQL. - */ - public SqlTreeNodeBean(BeanDescriptor desc, SqlTreeProperties props, boolean withId, boolean disableLazyLoad) { - this(null, null, desc, props, null, withId, null, null, disableLazyLoad); - } - /** * Construct for leaf node. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeRoot.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeRoot.java index 75cd58059..f3f027bce 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeRoot.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeRoot.java @@ -25,14 +25,6 @@ public final class SqlTreeNodeRoot extends SqlTreeNodeBean { this.includeJoin = includeJoin; } - /** - * Construct for raw sql named queries. - */ - public SqlTreeNodeRoot(BeanDescriptor desc, SqlTreeProperties props, boolean withId) { - super(desc, props, withId, false); - this.includeJoin = null; - } - /** * Set AsOf support (at root level). */ From 81de83a6e767a0d1c3fd62a179cd007a5dc3951c Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 20:23:11 +1200 Subject: [PATCH 49/65] #803 - Fix generics on findMap() to ... Map findMap(); --- .../java/com/avaje/ebean/EbeanServer.java | 2 +- .../java/com/avaje/ebean/ExpressionList.java | 2 +- src/main/java/com/avaje/ebean/Model.java | 2 +- src/main/java/com/avaje/ebean/Query.java | 4 +-- .../server/core/DefaultServer.java | 7 +++-- .../expression/DefaultExpressionList.java | 2 +- .../expression/FilterExpressionList.java | 2 +- .../server/expression/JunctionExpression.java | 2 +- .../server/querydefn/DefaultOrmQuery.java | 2 +- .../ebeaninternal/api/TDSpiEbeanServer.java | 2 +- .../tests/basic/TestLazyLoadInCache.java | 2 +- .../avaje/tests/basic/TestLoadBeanCache.java | 2 +- .../tests/query/TestQueryFindMapTypedKey.java | 30 ++++++++++++++----- .../avaje/tests/readaudit/TestReadAudit.java | 2 +- 14 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index f4710e709..6d13000b3 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -986,7 +986,7 @@ public interface EbeanServer { * @return the map of fetched beans. * @see Query#findMap() */ - Map findMap(Query query, Transaction transaction); + Map findMap(Query query, Transaction transaction); /** * Execute the query returning a list of values for a single property. diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index c0c8f6512..882fbdc36 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -203,7 +203,7 @@ public interface ExpressionList { * * @see Query#findMap() */ - Map findMap(); + Map findMap(); /** * Return a typed map specifying the key property and type. diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java index 3f0bf9606..4431c18de 100644 --- a/src/main/java/com/avaje/ebean/Model.java +++ b/src/main/java/com/avaje/ebean/Model.java @@ -660,7 +660,7 @@ public abstract class Model { *

    * Equivalent to {@link Query#findMap()} */ - public Map findMap() { + public Map findMap() { return query().findMap(); } diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 7fb526336..920a148f8 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -661,7 +661,7 @@ public interface Query { *

    *
    {@code
        *
    -   * Map map =
    +   * Map map =
        *   ebeanServer.find(Product.class)
        *     .setMapKey("sku")
        *     .findMap();
    @@ -670,7 +670,7 @@ public interface Query {
        *
        * @see EbeanServer#findMap(Query, Transaction)
        */
    -  Map findMap();
    +   Map findMap();
     
       /**
        * Return a typed map specifying the key property and type.
    diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
    index 7b2af928f..7c3e76a57 100644
    --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
    +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
    @@ -1134,18 +1134,18 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
       }
     
       @SuppressWarnings({ "unchecked", "rawtypes" })
    -  public  Map findMap(Query query, Transaction t) {
    +  public  Map findMap(Query query, Transaction t) {
     
         SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, t);
     
         Object result = request.getFromQueryCache();
         if (result != null) {
    -      return (Map) result;
    +      return (Map) result;
         }
     
         try {
           request.initTransIfRequired();
    -      return (Map) request.findMap();
    +      return (Map) request.findMap();
     
         } finally {
           request.endTransIfRequired();
    @@ -1153,6 +1153,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
       }
     
       @Override
    +  @SuppressWarnings("unchecked")
       public  List findSingleAttributeList(Query query, Transaction t) {
     
         SpiOrmQueryRequest request = createQueryRequest(Type.ATTRIBUTE, query, t);
    diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java
    index a1e97986c..3dbf67571 100644
    --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java
    +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java
    @@ -379,7 +379,7 @@ public class DefaultExpressionList implements SpiExpressionList {
       }
     
       @Override
    -  public Map findMap() {
    +  public  Map findMap() {
         return query.findMap();
       }
     
    diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java
    index 18284b842..cea91d4bf 100644
    --- a/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java
    +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/FilterExpressionList.java
    @@ -64,7 +64,7 @@ public class FilterExpressionList extends DefaultExpressionList {
       }
     
       @Override
    -  public Map findMap() {
    +  public  Map findMap() {
         return rootQuery.findMap();
       }
     
    diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
    index 6db932350..21a085ed6 100644
    --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
    +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java
    @@ -391,7 +391,7 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression
       }
     
       @Override
    -  public Map findMap() {
    +  public  Map findMap() {
         return exprList.findMap();
       }
     
    diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java
    index 179999d93..75ae46827 100644
    --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java
    +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java
    @@ -1142,7 +1142,7 @@ public class DefaultOrmQuery implements SpiQuery {
       }
     
       @Override
    -  public Map findMap() {
    +  public  Map findMap() {
         return server.findMap(this, null);
       }
     
    diff --git a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
    index be387934e..e7ea6a3bb 100644
    --- a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
    +++ b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java
    @@ -516,7 +516,7 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
       }
     
       @Override
    -  public  Map findMap(Query query, Transaction transaction) {
    +  public  Map findMap(Query query, Transaction transaction) {
         return null;
       }
     
    diff --git a/src/test/java/com/avaje/tests/basic/TestLazyLoadInCache.java b/src/test/java/com/avaje/tests/basic/TestLazyLoadInCache.java
    index 47c9d5a04..f1cb4a1c5 100644
    --- a/src/test/java/com/avaje/tests/basic/TestLazyLoadInCache.java
    +++ b/src/test/java/com/avaje/tests/basic/TestLazyLoadInCache.java
    @@ -22,7 +22,7 @@ public class TestLazyLoadInCache extends BaseTestCase {
     		
     		ResetBasicData.reset();
     		
    -		Map map = Ebean.find(Customer.class)
    +		Map map = Ebean.find(Customer.class)
     			.select("id, name")
     			.setLoadBeanCache(true)
     			.setReadOnly(true)
    diff --git a/src/test/java/com/avaje/tests/basic/TestLoadBeanCache.java b/src/test/java/com/avaje/tests/basic/TestLoadBeanCache.java
    index e688df5b1..6e950ee62 100644
    --- a/src/test/java/com/avaje/tests/basic/TestLoadBeanCache.java
    +++ b/src/test/java/com/avaje/tests/basic/TestLoadBeanCache.java
    @@ -17,7 +17,7 @@ public class TestLoadBeanCache extends BaseTestCase {
     		
     		ResetBasicData.reset();
     		
    -		Map map = Ebean.find(Country.class)
    +		Map map = Ebean.find(Country.class)
     			.setLoadBeanCache(true)
     			.setUseQueryCache(true)
     			.setReadOnly(true)
    diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindMapTypedKey.java b/src/test/java/com/avaje/tests/query/TestQueryFindMapTypedKey.java
    index 8aaa9c12d..6648eb5f1 100644
    --- a/src/test/java/com/avaje/tests/query/TestQueryFindMapTypedKey.java
    +++ b/src/test/java/com/avaje/tests/query/TestQueryFindMapTypedKey.java
    @@ -1,14 +1,16 @@
     package com.avaje.tests.query;
     
    -import java.util.Map;
    -
    -import org.junit.Assert;
    -import org.junit.Test;
    -
     import com.avaje.ebean.BaseTestCase;
     import com.avaje.ebean.Ebean;
     import com.avaje.tests.model.basic.Customer;
    +import com.avaje.tests.model.basic.Product;
     import com.avaje.tests.model.basic.ResetBasicData;
    +import org.junit.Test;
    +
    +import java.util.Map;
    +
    +import static org.assertj.core.api.Assertions.assertThat;
    +import static org.junit.Assert.assertNotNull;
     
     public class TestQueryFindMapTypedKey extends BaseTestCase {
     
    @@ -17,9 +19,21 @@ public class TestQueryFindMapTypedKey extends BaseTestCase {
     
         ResetBasicData.reset();
     
    -    Map map = Ebean.find(Customer.class).select("id, name")
    -        .findMap("name", String.class);
    +    Map productsBySku = Ebean.find(Product.class)
    +        .setMapKey("sku")
    +        .findMap();
    +
    +    assertThat(productsBySku).isNotEmpty();
    +
    +    Product desk = productsBySku.get("DSK1");
    +    assertNotNull(desk);
    +
    +    Map map = Ebean.find(Customer.class)
    +        .select("id, name")
    +        .setMapKey("name")
    +        .findMap();
    +
    +    assertNotNull(map);
     
    -    Assert.assertNotNull(map);
       }
     }
    diff --git a/src/test/java/com/avaje/tests/readaudit/TestReadAudit.java b/src/test/java/com/avaje/tests/readaudit/TestReadAudit.java
    index 578039966..927e75bba 100644
    --- a/src/test/java/com/avaje/tests/readaudit/TestReadAudit.java
    +++ b/src/test/java/com/avaje/tests/readaudit/TestReadAudit.java
    @@ -257,7 +257,7 @@ public class TestReadAudit extends BaseTestCase {
     
         resetCounters();
     
    -    Map list = server.find(EBasicChangeLog.class)
    +    Map list = server.find(EBasicChangeLog.class)
             .where().startsWith("shortDescription", "readAudit")
             .findMap();
     
    
    From 876476fdc150b6786995379c1d180a493edae81d Mon Sep 17 00:00:00 2001
    From: Robin Bygrave 
    Date: Thu, 4 Aug 2016 20:30:18 +1200
    Subject: [PATCH 50/65] #804 - Remove API - findMap(property, type) ... migrate
     to query.setMapKey()
    
    ---
     src/main/java/com/avaje/ebean/ExpressionList.java      |  5 -----
     src/main/java/com/avaje/ebean/Model.java               | 10 ----------
     src/main/java/com/avaje/ebean/Query.java               |  5 -----
     .../server/expression/DefaultExpressionList.java       |  5 -----
     .../server/expression/JunctionExpression.java          |  5 -----
     .../server/querydefn/DefaultOrmQuery.java              |  6 ------
     .../java/com/avaje/tests/text/json/TestJsonMap.java    |  2 +-
     7 files changed, 1 insertion(+), 37 deletions(-)
    
    diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java
    index 882fbdc36..1937ee002 100644
    --- a/src/main/java/com/avaje/ebean/ExpressionList.java
    +++ b/src/main/java/com/avaje/ebean/ExpressionList.java
    @@ -205,11 +205,6 @@ public interface ExpressionList {
        */
        Map findMap();
     
    -  /**
    -   * Return a typed map specifying the key property and type.
    -   */
    -   Map findMap(String keyProperty, Class keyType);
    -
       /**
        * Execute the query returning a list of values for a single property.
        *
    diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java
    index 4431c18de..4f5b7418c 100644
    --- a/src/main/java/com/avaje/ebean/Model.java
    +++ b/src/main/java/com/avaje/ebean/Model.java
    @@ -664,16 +664,6 @@ public abstract class Model {
           return query().findMap();
         }
     
    -    /**
    -     * Executes the query and returns the results as a map of the objects specifying the map key
    -     * property.
    -     * 

    - * Equivalent to {@link Query#findMap(String, Class)} - */ - public Map findMap(String keyProperty, Class keyType) { - return query().findMap(keyProperty, keyType); - } - /** * Executes a find row count query in a background thread. *

    diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 920a148f8..0c60ecd23 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -672,11 +672,6 @@ public interface Query { */ Map findMap(); - /** - * Return a typed map specifying the key property and type. - */ - Map findMap(String keyProperty, Class keyType); - /** * Execute the query returning a list of values for a single property. * diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index 3dbf67571..d5840c3a0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -383,11 +383,6 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findMap(); } - @Override - public Map findMap(String keyProperty, Class keyType) { - return query.findMap(keyProperty, keyType); - } - @Override public List findSingleAttributeList() { return query.findSingleAttributeList(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 21a085ed6..9132b0807 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -395,11 +395,6 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.findMap(); } - @Override - public Map findMap(String keyProperty, Class keyType) { - return exprList.findMap(keyProperty, keyType); - } - @Override public List findSingleAttributeList() { return exprList.findSingleAttributeList(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 75ae46827..2adcf19ad 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1148,12 +1148,6 @@ public class DefaultOrmQuery implements SpiQuery { @Override @SuppressWarnings("unchecked") - public Map findMap(String keyProperty, Class keyType) { - setMapKey(keyProperty); - return (Map) findMap(); - } - - @Override public List findSingleAttributeList() { return (List)server.findSingleAttributeList(this, null); } diff --git a/src/test/java/com/avaje/tests/text/json/TestJsonMap.java b/src/test/java/com/avaje/tests/text/json/TestJsonMap.java index 9caa18da8..ecf582b50 100644 --- a/src/test/java/com/avaje/tests/text/json/TestJsonMap.java +++ b/src/test/java/com/avaje/tests/text/json/TestJsonMap.java @@ -41,7 +41,7 @@ public class TestJsonMap extends BaseTestCase { ResetBasicData.reset(); - Map map = Ebean.find(Customer.class).findMap("id", String.class); + Map map = Ebean.find(Customer.class).findMap(); JsonContext jsonContext = Ebean.json(); JsonWriteOptions options = JsonWriteOptions.parsePath("(id,status,name)"); From 08e46d6bf31deeb18babf8bbddf29f93e4079f9d Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 22:49:07 +1200 Subject: [PATCH 51/65] #805 - ENH: Add BeanState.resetForInsert() ... This resets bean state such that a save() results in an insert --- src/main/java/com/avaje/ebean/BeanState.java | 5 ++ .../avaje/ebean/bean/EntityBeanIntercept.java | 7 +++ .../ebeaninternal/api/ScopedTransaction.java | 8 ++- .../ebeaninternal/api/SpiTransaction.java | 6 +++ .../server/core/BeanRequest.java | 4 +- .../server/core/DefaultBeanState.java | 5 ++ .../server/core/PersistRequestBean.java | 2 +- .../server/core/TransWrapper.java | 2 +- .../server/transaction/JdbcTransaction.java | 38 ++++++++++---- .../tests/transaction/TestBeanStateReset.java | 50 +++++++++++++++++++ .../transaction/TestTransactionCallback.java | 4 +- 11 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java diff --git a/src/main/java/com/avaje/ebean/BeanState.java b/src/main/java/com/avaje/ebean/BeanState.java index 68cd12ab5..a6708a783 100644 --- a/src/main/java/com/avaje/ebean/BeanState.java +++ b/src/main/java/com/avaje/ebean/BeanState.java @@ -120,4 +120,9 @@ public interface BeanState { * for a fully loaded entity bean. */ void setLoaded(); + + /** + * Reset the bean putting it into NEW state such that a save() results in an insert. + */ + void resetForInsert(); } \ No newline at end of file diff --git a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java index 1f9af8aa9..22d68e0e4 100644 --- a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java @@ -342,6 +342,13 @@ public final class EntityBeanIntercept implements Serializable { return state == STATE_LOADED; } + /** + * Set the bean into NEW state. + */ + public void setNew() { + this.state = STATE_NEW; + } + /** * Set the loaded state to true. *

    diff --git a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java index 44f7eb62c..6a5354061 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java @@ -29,10 +29,9 @@ public class ScopedTransaction implements SpiTransaction { public ScopedTransaction(ScopeTrans scopeTrans) { this.scopeTrans = scopeTrans; - this.transaction =scopeTrans.getTransaction(); + this.transaction = scopeTrans.getTransaction(); } - @Override public void commit() throws RollbackException { scopeTrans.commitTransaction(); @@ -49,6 +48,11 @@ public class ScopedTransaction implements SpiTransaction { scopeTrans.rollback(e); } + @Override + public void rollbackIfActive() { + transaction.rollbackIfActive(); + } + @Override public void setRollbackOnly() { scopeTrans.setRollbackOnly(); diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java b/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java index e51719579..0f3a6ae1e 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java @@ -220,6 +220,12 @@ public interface SpiTransaction extends Transaction { */ Connection getInternalConnection(); + /** + * Rollback if the transaction is active. This provides an internal + * mechanism for rollback failures occur on commit(). + */ + void rollbackIfActive(); + /** * Return true if the manyToMany intersection should be persisted for this particular relationship direction. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/BeanRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/BeanRequest.java index b5907bfe4..9ba4070e7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/BeanRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/BeanRequest.java @@ -68,11 +68,11 @@ public abstract class BeanRequest { public void rollbackTransIfRequired() { if (createdTransaction) { try { - transaction.rollback(); + transaction.rollbackIfActive(); } catch (Exception e) { // Just log this and carry on. A previous exception has been // thrown and if this rollback throws exception it likely means - // that the connection is broken (and the datasource and db will cleanup) + // that the connection is broken (and the dataSource and db will cleanup) log.error("Error trying to rollback a transaction (after a prior exception thrown)", e); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java index d31135827..1a20d6b04 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java @@ -84,4 +84,9 @@ public class DefaultBeanState implements BeanState { public boolean isDisableLazyLoad() { return intercept.isDisableLazyLoad(); } + + @Override + public void resetForInsert() { + intercept.setNew(); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java index 55c997538..fa954bcff 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java @@ -821,7 +821,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } /** - * Add the bean to the TransactionEvent. This will be used by TransactionManager to synch Cache, + * Add the bean to the TransactionEvent. This will be used by TransactionManager to sync Cache, * Cluster and text indexes. */ private void addEvent() { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/TransWrapper.java b/src/main/java/com/avaje/ebeaninternal/server/core/TransWrapper.java index 3ad7b74bc..36fb3de0f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/TransWrapper.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/TransWrapper.java @@ -41,7 +41,7 @@ final class TransWrapper { void rollbackIfCreated() { if (wasCreated){ - transaction.rollback(); + transaction.rollbackIfActive(); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java index 79fe82379..1cc759447 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java @@ -913,28 +913,27 @@ public class JdbcTransaction implements SpiTransaction { throw new IllegalStateException(illegalStateMessage); } - firePreCommit(); - try { if (queryOnly) { - // can rollback or just close for performance connectionEndForQueryOnly(); + } else { - // commit if (batchControl != null && !batchControl.isEmpty()) { batchControl.flush(); } + firePreCommit(); + // only performCommit can throw an exception performCommit(); + firePostCommit(); + notifyCommit(); } } catch (Exception e) { + doRollback(e); throw new RollbackException(e); } finally { - // these will not throw an exception - firePostCommit(); deactivate(); - notifyCommit(); } } @@ -959,6 +958,16 @@ public class JdbcTransaction implements SpiTransaction { this.rollbackOnly = true; } + /** + * Perform rollback is the transaction is still active. + */ + @Override + public void rollbackIfActive() { + if (isActive()) { + rollback(null); + } + } + /** * Rollback the transaction. */ @@ -976,17 +985,26 @@ public class JdbcTransaction implements SpiTransaction { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } + try { + doRollback(cause); + } finally { + deactivate(); + } + } + + /** + * Perform the jdbc rollback and fire any registered callbacks. + */ + private void doRollback(Throwable cause) { firePreRollback(); try { performRollback(); - - } catch (Exception ex) { + } catch (SQLException ex) { throw new PersistenceException(ex); } finally { // these will not throw an exception firePostRollback(); - deactivate(); notifyRollback(cause); } } diff --git a/src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java b/src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java new file mode 100644 index 000000000..9825834ec --- /dev/null +++ b/src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java @@ -0,0 +1,50 @@ +package com.avaje.tests.transaction; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.tests.model.m2m.MnyB; +import com.avaje.tests.model.m2m.MnyC; +import org.avaje.ebeantest.LoggedSqlCollector; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.PersistenceException; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestBeanStateReset extends BaseTestCase { + + private static final Logger logger = LoggerFactory.getLogger(TestBeanStateReset.class); + + @Test + public void resetForInsert() { + + // setup to fail foreign key constraint + MnyC c = new MnyC(); + c.setId(Long.MAX_VALUE); + + MnyB b = new MnyB(); + b.getCs().add(c); + + try { + // inserts of b succeeds but intersection insert fails FK check on c + b.save(); + + } catch (PersistenceException e) { + logger.info("expected error " + e.getMessage()); + + Ebean.getBeanState(b).resetForInsert(); + b.getCs().clear(); + + LoggedSqlCollector.start(); + b.setName("mod"); + b.save(); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("insert into mny_b (id, name, version, when_created, when_modified, a_id) values ("); + } + + } +} diff --git a/src/test/java/com/avaje/tests/transaction/TestTransactionCallback.java b/src/test/java/com/avaje/tests/transaction/TestTransactionCallback.java index e8f3ba85c..f4e7f3370 100644 --- a/src/test/java/com/avaje/tests/transaction/TestTransactionCallback.java +++ b/src/test/java/com/avaje/tests/transaction/TestTransactionCallback.java @@ -3,6 +3,7 @@ package com.avaje.tests.transaction; import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; import com.avaje.ebean.EbeanServer; +import com.avaje.ebean.Transaction; import com.avaje.ebean.TransactionCallbackAdapter; import org.junit.Test; @@ -27,8 +28,9 @@ public class TestTransactionCallback extends BaseTestCase { public void test_commitAndRollback() { - Ebean.beginTransaction(); + Transaction txn = Ebean.beginTransaction(); Ebean.register(new MyCallback()); + txn.getConnection(); Ebean.commitTransaction(); assertEquals(1, countPreCommit); From e30ad80f5fdab8596b4376a6f0697fc18a358de8 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 23:02:26 +1200 Subject: [PATCH 52/65] #806 - Deprecate OnQueryOnly.CLOSE ... --- .../config/dbplatform/DatabasePlatform.java | 6 --- .../ExplicitTransactionManager.java | 8 +--- .../server/transaction/JdbcTransaction.java | 22 +++------- .../transaction/TransactionManager.java | 41 ------------------- 4 files changed, 7 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java index 952e71b51..cd243e4e4 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java @@ -33,12 +33,6 @@ public class DatabasePlatform { */ ROLLBACK, - /** - * Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases - * as a performance optimisation. - */ - CLOSE, - /** * Commit the transaction */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java index c93d4a592..1a6134703 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java @@ -44,11 +44,7 @@ public class ExplicitTransactionManager extends TransactionManager { return DatabasePlatform.OnQueryOnly.valueOf(systemPropertyValue.trim().toUpperCase()); } - if (DatabasePlatform.OnQueryOnly.CLOSE.equals(dbPlatformOnQueryOnly)) { - // Not using OnQueryOnly.CLOSE with ExplicitJdbcTransaction - return DatabasePlatform.OnQueryOnly.COMMIT; - } - // default to commit if not defined on the platform - return dbPlatformOnQueryOnly == null ? DatabasePlatform.OnQueryOnly.COMMIT : dbPlatformOnQueryOnly; + // default to rollback if not defined on the platform + return dbPlatformOnQueryOnly == null ? DatabasePlatform.OnQueryOnly.ROLLBACK : dbPlatformOnQueryOnly; } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java index 1cc759447..75ad78b5f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java @@ -860,26 +860,14 @@ public class JdbcTransaction implements SpiTransaction { } /** - * Rollback, Commit or Close for query only transaction. - *

    - * For a transaction that was used for queries only we can choose to either - * rollback or just close the connection for performance. - *

    + * Rollback or Commit for query only transaction. */ protected void connectionEndForQueryOnly() { try { - switch (onQueryOnly) { - case ROLLBACK: - performRollback(); - break; - case COMMIT: - performCommit(); - break; - case CLOSE: - // valid at READ COMMITTED Isolation - break; - default: - performRollback(); + if (onQueryOnly == OnQueryOnly.COMMIT) { + performCommit(); + } else { + performRollback(); } } catch (SQLException e) { logger.error("Error when ending a query only transaction via " + onQueryOnly, e); diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java index 47abc01b5..dc1402503 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java @@ -192,51 +192,10 @@ public class TransactionManager { return OnQueryOnly.valueOf(systemPropertyValue.trim().toUpperCase()); } - if (OnQueryOnly.CLOSE.equals(dbPlatformOnQueryOnly)) { - // check for read committed isolation level - if (!isReadCommittedIsolation(ds)) { - logger.warn("Ignoring DatabasePlatform.OnQueryOnly.CLOSE as the transaction Isolation Level is not READ_COMMITTED"); - // we will just use ROLLBACK and ignore the desired optimisation - return OnQueryOnly.ROLLBACK; - } else { - // will use the OnQueryOnly.CLOSE optimisation - return OnQueryOnly.CLOSE; - } - } // default to rollback if not defined on the platform return dbPlatformOnQueryOnly == null ? OnQueryOnly.ROLLBACK : dbPlatformOnQueryOnly; } - /** - * Return true if the isolation level is read committed. - */ - protected boolean isReadCommittedIsolation(DataSource ds) { - - if (DbOffline.isSet()) { - return true; - } - Connection c = null; - try { - c = ds.getConnection(); - - int isolationLevel = c.getTransactionIsolation(); - return (isolationLevel == Connection.TRANSACTION_READ_COMMITTED); - - } catch (SQLException ex) { - String m = "Errored trying to determine the default Isolation Level"; - throw new PersistenceException(m, ex); - - } finally { - try { - if (c != null) { - c.close(); - } - } catch (SQLException ex) { - logger.error("closing connection", ex); - } - } - } - public String getServerName() { return serverName; } From 479ac38537723e3a57de40b05650d4e0d0342238 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 23:17:57 +1200 Subject: [PATCH 53/65] #807 - Deprecate TransactionEventListener ... migrate to TransactionCallback --- .../com/avaje/ebean/config/ServerConfig.java | 31 ---------- .../ebean/event/TransactionEventListener.java | 18 ------ .../TransactionEventListenerAdapter.java | 18 ------ .../server/core/DefaultContainer.java | 1 - .../server/core/InternalConfiguration.java | 6 +- .../server/core/bootup/BootupClasses.java | 30 --------- .../AutoCommitTransactionManager.java | 7 +-- .../ExplicitTransactionManager.java | 7 +-- .../transaction/TransactionManager.java | 20 +----- .../event/MyTestTransactionEventListener.java | 43 ------------- .../basic/event/TestTransactionEvent.java | 62 ------------------- 11 files changed, 11 insertions(+), 232 deletions(-) delete mode 100644 src/main/java/com/avaje/ebean/event/TransactionEventListener.java delete mode 100644 src/main/java/com/avaje/ebean/event/TransactionEventListenerAdapter.java delete mode 100644 src/test/java/com/avaje/tests/basic/event/MyTestTransactionEventListener.java delete mode 100644 src/test/java/com/avaje/tests/basic/event/TestTransactionEvent.java diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java index 0db26cc5a..9dd0d05bb 100644 --- a/src/main/java/com/avaje/ebean/config/ServerConfig.java +++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java @@ -14,7 +14,6 @@ import com.avaje.ebean.event.BeanPostLoad; import com.avaje.ebean.event.BeanQueryAdapter; import com.avaje.ebean.event.BulkTableEventListener; import com.avaje.ebean.event.ServerConfigStartup; -import com.avaje.ebean.event.TransactionEventListener; import com.avaje.ebean.event.changelog.ChangeLogListener; import com.avaje.ebean.event.changelog.ChangeLogPrepare; import com.avaje.ebean.event.changelog.ChangeLogRegister; @@ -331,7 +330,6 @@ public class ServerConfig { private List queryAdapters = new ArrayList(); private List bulkTableEventListeners = new ArrayList(); private List configStartupListeners = new ArrayList(); - private List transactionEventListeners = new ArrayList(); /** * By default inserts are included in the change log. @@ -2052,35 +2050,6 @@ public class ServerConfig { this.persistControllers = persistControllers; } - /** - * Register a TransactionEventListener instance - *

    - * Note alternatively you can use {@link #setTransactionEventListeners(List)} - * to set all the TransactionEventListener instances. - *

    - */ - public void add(TransactionEventListener listener) { - transactionEventListeners.add(listener); - } - - /** - * Return the TransactionEventListener instances. - */ - public List getTransactionEventListeners() { - return transactionEventListeners; - } - - /** - * Register all the TransactionEventListener instances. - *

    - * Note alternatively you can use {@link #add(TransactionEventListener)} to - * add TransactionEventListener instances one at a time. - *

    - */ - public void setTransactionEventListeners(List transactionEventListeners) { - this.transactionEventListeners = transactionEventListeners; - } - /** * Register a BeanPersistListener instance. *

    diff --git a/src/main/java/com/avaje/ebean/event/TransactionEventListener.java b/src/main/java/com/avaje/ebean/event/TransactionEventListener.java deleted file mode 100644 index fb9ab50c7..000000000 --- a/src/main/java/com/avaje/ebean/event/TransactionEventListener.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.avaje.ebean.event; - -import com.avaje.ebean.Transaction; - -/** - * Used to get notified about commit or rollback of a transaction - */ -public interface TransactionEventListener { - /** - * Called after the transaction has been committed - */ - void postTransactionCommit(Transaction tx); - - /** - * Called after the transaction has been rolled back - */ - void postTransactionRollback(Transaction tx, Throwable cause); -} diff --git a/src/main/java/com/avaje/ebean/event/TransactionEventListenerAdapter.java b/src/main/java/com/avaje/ebean/event/TransactionEventListenerAdapter.java deleted file mode 100644 index 376dfdfbe..000000000 --- a/src/main/java/com/avaje/ebean/event/TransactionEventListenerAdapter.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.avaje.ebean.event; - -import com.avaje.ebean.Transaction; - -/** - * A no operation implementation of TransactionEventListener. Objects extending - * this need to only override the methods they want to. - */ -public abstract class TransactionEventListenerAdapter implements TransactionEventListener { - - public void postTransactionCommit(Transaction tx) { - // do nothing by default - } - - public void postTransactionRollback(Transaction tx, Throwable cause) { - // do nothing by default - } -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java index 210fde590..0f25e5cc7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java @@ -195,7 +195,6 @@ public class DefaultContainer implements SpiContainer { bootup.addPersistControllers(serverConfig.getPersistControllers()); bootup.addPostLoaders(serverConfig.getPostLoaders()); bootup.addFindControllers(serverConfig.getFindControllers()); - bootup.addTransactionEventListeners(serverConfig.getTransactionEventListeners()); bootup.addPersistListeners(serverConfig.getPersistListeners()); bootup.addQueryAdapters(serverConfig.getQueryAdapters()); bootup.addServerConfigStartup(serverConfig.getServerConfigStartupListeners()); diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java index 219acce17..caf82e185 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java @@ -340,14 +340,14 @@ public class InternalConfiguration { boolean localL2 = cacheManager.isLocalL2Caching(); if (serverConfig.isExplicitTransactionBeginMode()) { - return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses()); + return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager); } if (isAutoCommitMode()) { - return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses()); + return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager); } - return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses()); + return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager); } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/bootup/BootupClasses.java b/src/main/java/com/avaje/ebeaninternal/server/core/bootup/BootupClasses.java index 2413c6caa..d846536d8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/bootup/BootupClasses.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/bootup/BootupClasses.java @@ -10,7 +10,6 @@ import com.avaje.ebean.event.BeanPersistListener; import com.avaje.ebean.event.BeanPostLoad; import com.avaje.ebean.event.BeanQueryAdapter; import com.avaje.ebean.event.ServerConfigStartup; -import com.avaje.ebean.event.TransactionEventListener; import com.avaje.ebean.event.changelog.ChangeLogListener; import com.avaje.ebean.event.changelog.ChangeLogPrepare; import com.avaje.ebean.event.changelog.ChangeLogRegister; @@ -54,8 +53,6 @@ public class BootupClasses implements ClassFilter { private final List> beanPostLoadList = new ArrayList>(); - private final List> transactionEventListenerList = new ArrayList>(); - private final List> beanFindControllerList = new ArrayList>(); private final List> beanQueryAdapterList = new ArrayList>(); @@ -70,7 +67,6 @@ public class BootupClasses implements ClassFilter { private final List beanPostLoadInstances = new ArrayList(); private final List persistListenerInstances = new ArrayList(); private final List queryAdapterInstances = new ArrayList(); - private final List transactionEventListenerInstances = new ArrayList(); private Class changeLogPrepareClass; private Class changeLogListenerClass; @@ -181,19 +177,6 @@ public class BootupClasses implements ClassFilter { } } - /** - * Add TransactionEventListeners instances. - */ - public void addTransactionEventListeners(List transactionEventListeners) { - if (transactionEventListeners != null) { - for (TransactionEventListener c : transactionEventListeners) { - this.transactionEventListenerInstances.add(c); - // don't automatically instantiate - this.transactionEventListenerList.remove(c.getClass()); - } - } - } - public void addPersistListeners(List listenerInstances) { if (listenerInstances != null) { for (BeanPersistListener l : listenerInstances) { @@ -351,14 +334,6 @@ public class BootupClasses implements ClassFilter { return idGeneratorInstances; } - public List getTransactionEventListeners() { - // add class registered TransactionEventListener to the already created instances - for (Class cls : transactionEventListenerList) { - createAdd(cls, transactionEventListenerInstances); - } - return transactionEventListenerInstances; - } - /** * Return the list of Embeddable classes. */ @@ -440,11 +415,6 @@ public class BootupClasses implements ClassFilter { interesting = true; } - if (TransactionEventListener.class.isAssignableFrom(cls)) { - transactionEventListenerList.add(cls); - interesting = true; - } - if (ScalarType.class.isAssignableFrom(cls)) { scalarTypeList.add(cls); interesting = true; diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/AutoCommitTransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/AutoCommitTransactionManager.java index af04c6ad5..c2c40ebe4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/AutoCommitTransactionManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/AutoCommitTransactionManager.java @@ -3,10 +3,9 @@ package com.avaje.ebeaninternal.server.transaction; import com.avaje.ebean.BackgroundExecutor; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebeaninternal.api.SpiTransaction; -import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor; import com.avaje.ebeaninternal.server.cluster.ClusterManager; -import com.avaje.ebeaninternal.server.core.bootup.BootupClasses; import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager; +import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor; import java.sql.Connection; @@ -18,9 +17,9 @@ import java.sql.Connection; public class AutoCommitTransactionManager extends TransactionManager { public AutoCommitTransactionManager(boolean localL2Caching, ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor, - DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) { + DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr) { - super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses); + super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr); } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java index 1a6134703..70b4ee7b1 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/ExplicitTransactionManager.java @@ -4,10 +4,9 @@ import com.avaje.ebean.BackgroundExecutor; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.DatabasePlatform; import com.avaje.ebeaninternal.api.SpiTransaction; -import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor; import com.avaje.ebeaninternal.server.cluster.ClusterManager; -import com.avaje.ebeaninternal.server.core.bootup.BootupClasses; import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager; +import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor; import javax.sql.DataSource; import java.sql.Connection; @@ -18,9 +17,9 @@ import java.sql.Connection; public class ExplicitTransactionManager extends TransactionManager { public ExplicitTransactionManager(boolean localL2Caching, ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor, - DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) { + DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr) { - super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses); + super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr); } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java index dc1402503..4d42916e4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionManager.java @@ -4,8 +4,6 @@ import com.avaje.ebean.BackgroundExecutor; import com.avaje.ebean.config.PersistBatch; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly; -import com.avaje.ebean.dbmigration.DbOffline; -import com.avaje.ebean.event.TransactionEventListener; import com.avaje.ebean.event.changelog.ChangeLogListener; import com.avaje.ebean.event.changelog.ChangeLogPrepare; import com.avaje.ebean.event.changelog.ChangeSet; @@ -14,11 +12,10 @@ import com.avaje.ebeaninternal.api.TransactionEvent; import com.avaje.ebeaninternal.api.TransactionEventTable; import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD; import com.avaje.ebeaninternal.server.cluster.ClusterManager; -import com.avaje.ebeaninternal.server.core.bootup.BootupClasses; import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager; -import org.avaje.datasource.DataSourcePool; import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor; import com.avaje.ebeanservice.docstore.api.DocStoreUpdates; +import org.avaje.datasource.DataSourcePool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -92,8 +89,6 @@ public class TransactionManager { protected final BulkEventListenerMap bulkEventListenerMap; - protected final TransactionEventListener[] transactionEventListeners; - /** * Used to prepare the change set setting user context information in the * foreground thread before logging. @@ -115,7 +110,7 @@ public class TransactionManager { * Create the TransactionManager */ public TransactionManager(boolean localL2Caching, ServerConfig config, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor, - DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) { + DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr) { this.skipCacheAfterWrite = config.isSkipCacheAfterWrite(); this.localL2Caching = localL2Caching; @@ -133,9 +128,6 @@ public class TransactionManager { this.docStoreUpdateProcessor = docStoreUpdateProcessor; this.bulkEventListenerMap = new BulkEventListenerMap(config.getBulkTableEventListeners()); - List transactionEventListeners = bootupClasses.getTransactionEventListeners(); - this.transactionEventListeners = transactionEventListeners.toArray(new TransactionEventListener[transactionEventListeners.size()]); - this.prefix = ""; this.externalTransPrefix = "e"; @@ -311,10 +303,6 @@ public class TransactionManager { TXN_LOGGER.debug(msg); } - for (TransactionEventListener listener : transactionEventListeners) { - listener.postTransactionRollback(transaction, cause); - } - } catch (Exception ex) { logger.error("Error while notifying TransactionEventListener of rollback event", ex); } @@ -369,10 +357,6 @@ public class TransactionManager { postCommit.notifyLocalCache(); backgroundExecutor.execute(postCommit.backgroundNotify()); - for (TransactionEventListener listener : transactionEventListeners) { - listener.postTransactionCommit(transaction); - } - } catch (Exception ex) { logger.error("NotifyOfCommit failed. L2 Cache potentially not notified.", ex); } diff --git a/src/test/java/com/avaje/tests/basic/event/MyTestTransactionEventListener.java b/src/test/java/com/avaje/tests/basic/event/MyTestTransactionEventListener.java deleted file mode 100644 index abe27803c..000000000 --- a/src/test/java/com/avaje/tests/basic/event/MyTestTransactionEventListener.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.avaje.tests.basic.event; - -import com.avaje.ebean.Transaction; -import com.avaje.ebean.event.TransactionEventListener; - -public class MyTestTransactionEventListener implements TransactionEventListener { - private volatile static boolean doTest = false; - - private static Transaction lastCommitted; - private static Transaction lastRollbacked; - - public void postTransactionCommit(Transaction tx) { - if (!doTest) { - return; - } - - lastCommitted = tx; - } - - public void postTransactionRollback(Transaction tx, Throwable cause) { - if (!doTest) { - return; - } - - lastRollbacked = tx; - } - - public static void setDoTest(boolean doTest) { - MyTestTransactionEventListener.doTest = doTest; - - // reset what we've recorded so far - lastCommitted = null; - lastRollbacked = null; - } - - public static Transaction getLastCommitted() { - return lastCommitted; - } - - public static Transaction getLastRollbacked() { - return lastRollbacked; - } -} diff --git a/src/test/java/com/avaje/tests/basic/event/TestTransactionEvent.java b/src/test/java/com/avaje/tests/basic/event/TestTransactionEvent.java deleted file mode 100644 index 6a36c862e..000000000 --- a/src/test/java/com/avaje/tests/basic/event/TestTransactionEvent.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.avaje.tests.basic.event; - -import junit.framework.TestCase; - -import com.avaje.ebean.Ebean; -import com.avaje.ebean.Transaction; -import com.avaje.tests.model.basic.TWithPreInsert; - -public class TestTransactionEvent extends TestCase { - - @Override - protected void tearDown() throws Exception { - MyTestTransactionEventListener.setDoTest(false); - } - - @Override - protected void setUp() throws Exception { - MyTestTransactionEventListener.setDoTest(true); - } - - public void test() { - - assertNull(MyTestTransactionEventListener.getLastCommitted()); - assertNull(MyTestTransactionEventListener.getLastRollbacked()); - - final Object myUserObject = new Object(); - - Transaction tx = Ebean.beginTransaction(); - tx.putUserObject("myUserObject", myUserObject); - - TWithPreInsert e = new TWithPreInsert(); - e.setTitle("Mister Transaction1"); - Ebean.save(e); - - tx.commit(); - - assertNotNull(MyTestTransactionEventListener.getLastCommitted()); - assertNotNull(MyTestTransactionEventListener.getLastCommitted().getUserObject("myUserObject")); - assertSame(MyTestTransactionEventListener.getLastCommitted().getUserObject("myUserObject"), myUserObject); - assertNull(MyTestTransactionEventListener.getLastRollbacked()); - - Transaction tx2 = Ebean.beginTransaction(); - tx2.putUserObject("myUserObject2", myUserObject); - - TWithPreInsert e2 = new TWithPreInsert(); - e2.setTitle("Mister Transaction2"); - Ebean.save(e2); - - tx2.rollback(); - - assertNotNull(MyTestTransactionEventListener.getLastCommitted()); - assertNotNull(MyTestTransactionEventListener.getLastRollbacked()); - - assertNotSame(MyTestTransactionEventListener.getLastCommitted(), MyTestTransactionEventListener.getLastRollbacked()); - - assertNotNull(MyTestTransactionEventListener.getLastCommitted().getUserObject("myUserObject")); - assertSame(MyTestTransactionEventListener.getLastCommitted().getUserObject("myUserObject"), myUserObject); - - assertNotNull(MyTestTransactionEventListener.getLastRollbacked().getUserObject("myUserObject2")); - assertSame(MyTestTransactionEventListener.getLastRollbacked().getUserObject("myUserObject2"), myUserObject); - } -} From 3344f0ddb02e386c8949dfd7197e8e828247b616 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 4 Aug 2016 23:25:50 +1200 Subject: [PATCH 54/65] Refactor - remove unused method JdbcTransaction.notifyQueryOnly(). --- .../ebeaninternal/server/transaction/JdbcTransaction.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java index 75ad78b5f..adb8433ba 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java @@ -853,12 +853,6 @@ public class JdbcTransaction implements SpiTransaction { } } - protected void notifyQueryOnly() { - if (manager != null) { - manager.notifyOfQueryOnly(this); - } - } - /** * Rollback or Commit for query only transaction. */ From 16be213faff696b3a4ce564a674cf18edecbb4db Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 10:39:17 +1200 Subject: [PATCH 55/65] #808 - ENH: Add Transaction commitAndContinue() ... --- .../java/com/avaje/ebean/Transaction.java | 44 ++++- .../ebeaninternal/api/ScopedTransaction.java | 5 + .../server/transaction/JdbcTransaction.java | 53 ++++- .../java/com/avaje/ebean/BaseTestCase.java | 2 +- .../java/com/avaje/tests/model/m2m/MnyB.java | 7 + .../transaction/TestCommitAndContinue.java | 183 ++++++++++++++++++ 6 files changed, 280 insertions(+), 14 deletions(-) create mode 100644 src/test/java/com/avaje/tests/transaction/TestCommitAndContinue.java diff --git a/src/main/java/com/avaje/ebean/Transaction.java b/src/main/java/com/avaje/ebean/Transaction.java index 526fe28bb..560a7278b 100644 --- a/src/main/java/com/avaje/ebean/Transaction.java +++ b/src/main/java/com/avaje/ebean/Transaction.java @@ -54,13 +54,52 @@ public interface Transaction extends Closeable { */ void setReadOnly(boolean readOnly); + /** + * Commits the transaction at this point with the expectation that another + * commit (or rollback or end) will occur later to complete the transaction. + *

    + * This is similar to commit() but leaves the transaction "Active". + *

    + *

    Functions/h3> + *
      + *
    • Flush the JDBC batch buffer
    • + *
    • Call commit on the underlying JDBC connection
    • + *
    • Trigger any registered TransactionCallbacks
    • + *
    • Perform post-commit processing updating L2 cache, ElasticSearch etc
    • + *
    + */ + void commitAndContinue() throws RollbackException; + /** * Commit the transaction. + *

    + * This performs commit and completes the transaction closing underlying resources and + * marking the transaction as "In active". + *

    + *

    Functions/h3> + *
      + *
    • Flush the JDBC batch buffer
    • + *
    • Call commit on the underlying JDBC connection
    • + *
    • Trigger any registered TransactionCallbacks
    • + *
    • Perform post-commit processing updating L2 cache, ElasticSearch etc
    • + *
    • Close any underlying resources, closing the underlying JDBC connection
    • + *
    • Mark the transaction as "Inactive"
    • + *
    */ void commit() throws RollbackException; /** * Rollback the transaction. + *

    + * This performs rollback, closes underlying resources and marks the transaction as "In active". + *

    + *

    Functions/h3> + *
      + *
    • Call rollback on the underlying JDBC connection
    • + *
    • Trigger any registered TransactionCallbacks
    • + *
    • Close any underlying resources, closing the underlying JDBC connection
    • + *
    • Mark the transaction as "Inactive"
    • + *
    */ void rollback() throws PersistenceException; @@ -422,9 +461,8 @@ public interface Transaction extends Closeable { /** * Add an arbitrary user object to the transaction. The objects added have no - * impact on any internals of ebena and are solely meant as a convenient - * method push user information to e.g. the - * {@link com.avaje.ebean.event.TransactionEventListener}. + * impact on any internals of ebean and are solely meant as a convenient + * method push user information (although somewhat replaced by TransactionCallback). */ void putUserObject(String name, Object value); diff --git a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java index 6a5354061..0d29f3aaf 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java @@ -32,6 +32,11 @@ public class ScopedTransaction implements SpiTransaction { this.transaction = scopeTrans.getTransaction(); } + @Override + public void commitAndContinue() throws RollbackException { + transaction.commitAndContinue(); + } + @Override public void commit() throws RollbackException { scopeTrans.commitTransaction(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java index adb8433ba..80f2ef1d9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java @@ -882,6 +882,48 @@ public class JdbcTransaction implements SpiTransaction { connection.commit(); } + /** + * Batch flush, jdbc commit, trigger registered TransactionCallbacks, notify l2 cache etc. + */ + private void flushCommitAndNotify() throws SQLException { + if (batchControl != null && !batchControl.isEmpty()) { + batchControl.flush(); + } + firePreCommit(); + // only performCommit can throw an exception + performCommit(); + firePostCommit(); + notifyCommit(); + } + + /** + * Perform a commit, fire callbacks and notify l2 cache etc. + *

    + * This leaves the transaction active and expects another commit + * to occur later (which closes the underlying connection etc). + *

    + */ + @Override + public void commitAndContinue() throws RollbackException { + if (rollbackOnly) { + return; + } + if (!isActive()) { + throw new IllegalStateException(illegalStateMessage); + } + try { + flushCommitAndNotify(); + // the event has been sent to the transaction manager + // for postCommit processing (l2 cache updates etc) + // start a new transaction event + event = new TransactionEvent(); + + } catch (Exception e) { + doRollback(e); + throw new RollbackException(e); + } + } + /** * Commit the transaction. */ @@ -894,20 +936,11 @@ public class JdbcTransaction implements SpiTransaction { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } - try { if (queryOnly) { connectionEndForQueryOnly(); - } else { - if (batchControl != null && !batchControl.isEmpty()) { - batchControl.flush(); - } - firePreCommit(); - // only performCommit can throw an exception - performCommit(); - firePostCommit(); - notifyCommit(); + flushCommitAndNotify(); } } catch (Exception e) { diff --git a/src/test/java/com/avaje/ebean/BaseTestCase.java b/src/test/java/com/avaje/ebean/BaseTestCase.java index e6be4834e..614a8824e 100644 --- a/src/test/java/com/avaje/ebean/BaseTestCase.java +++ b/src/test/java/com/avaje/ebean/BaseTestCase.java @@ -13,7 +13,7 @@ public class BaseTestCase { static { logger.debug("... preStart"); - if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent","debug=1;packages=com.avaje.tests,org.avaje.test")) { + if (!AgentLoader.loadAgentFromClasspath("ebean-agent","debug=1;packages=com.avaje.tests,org.avaje.test")) { logger.info("avaje-ebeanorm-agent not found in classpath - not dynamically loaded"); } } diff --git a/src/test/java/com/avaje/tests/model/m2m/MnyB.java b/src/test/java/com/avaje/tests/model/m2m/MnyB.java index 6009cb81d..371d2f994 100644 --- a/src/test/java/com/avaje/tests/model/m2m/MnyB.java +++ b/src/test/java/com/avaje/tests/model/m2m/MnyB.java @@ -19,6 +19,13 @@ public class MnyB extends BaseModel { @ManyToMany(cascade = CascadeType.REMOVE) List cs; + public MnyB(String name) { + this.name = name; + } + + public MnyB() { + } + public String getName() { return name; } diff --git a/src/test/java/com/avaje/tests/transaction/TestCommitAndContinue.java b/src/test/java/com/avaje/tests/transaction/TestCommitAndContinue.java new file mode 100644 index 000000000..74f7e5b94 --- /dev/null +++ b/src/test/java/com/avaje/tests/transaction/TestCommitAndContinue.java @@ -0,0 +1,183 @@ +package com.avaje.tests.transaction; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.EbeanServer; +import com.avaje.ebean.Transaction; +import com.avaje.ebean.annotation.Transactional; +import com.avaje.tests.model.m2m.MnyB; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class TestCommitAndContinue extends BaseTestCase { + + private static final Logger logger = LoggerFactory.getLogger("org.avaje.ebean.TXN"); + + @Test + @Transactional + public void transactional_partialSuccess() { + + MnyB a = new MnyB("a100"); + MnyB b = new MnyB("b200"); + + a.save(); + + // commit at this point + Ebean.currentTransaction().commitAndContinue(); + + try { + b.save(); + + // some error occurs + throw new IllegalStateException(); + + } catch (IllegalStateException e) { + // mark the transaction as rollback + Ebean.currentTransaction().setRollbackOnly(); + + // use a different transaction to assert + EbeanServer server = Ebean.getDefaultServer(); + Transaction anotherTxn = server.createTransaction(); + + // success prior to commitAndContinue + assertNotNull(server.find(MnyB.class, a.getId(), anotherTxn)); + + // insert failed after commitAndContinue + assertNull(server.find(MnyB.class, b.getId(), anotherTxn)); + } + } + + /** + * The @Transactional is nicer to me. + */ + @Test + public void tryFinally_partialSuccess() { + + MnyB a = new MnyB("a100"); + MnyB b = new MnyB("b200"); + + EbeanServer server = Ebean.getDefaultServer(); + Transaction txn = server.beginTransaction(); + try { + a.save(); + // commit at this point + txn.commitAndContinue(); + + try { + b.save(); + + // some error occurs + throw new IllegalStateException(); + + } catch (IllegalStateException e) { + // mark the transaction as rollback + txn.setRollbackOnly(); + + // use a different transaction to assert + Transaction anotherTxn = server.createTransaction(); + // success prior to commitAndContinue + assertNotNull(server.find(MnyB.class, a.getId(), anotherTxn)); + // insert failed after commitAndContinue + assertNull(server.find(MnyB.class, b.getId(), anotherTxn)); + } + + // does not commit due to the txn.setRollbackOnly(); + txn.commit(); + + } finally { + server.endTransaction(); + } + } + + @Test + @Transactional + public void transactional_partialSuccess_secondTransactionInsert() { + + MnyB a = new MnyB("a100"); + MnyB b = new MnyB("b200"); + MnyB c = new MnyB("c300"); + + a.save(); + + // commit at this point + Ebean.currentTransaction().commitAndContinue(); + + try { + b.save(); + + // some error occurs + throw new IllegalStateException(); + + } catch (IllegalStateException e) { + // mark the transaction as rollback + Ebean.currentTransaction().setRollbackOnly(); + + // use a different transaction to do something useful + EbeanServer server = Ebean.getDefaultServer(); + Transaction txn2 = server.createTransaction(); + try { + server.save(c, txn2); + txn2.commit(); + } finally { + txn2.end(); + } + } + + // asserts + + EbeanServer server = Ebean.getDefaultServer(); + Transaction txnForAssert = server.createTransaction(); + + // success prior to commitAndContinue + assertNotNull(server.find(MnyB.class, a.getId(), txnForAssert)); + + // insert failed after commitAndContinue + assertNull(server.find(MnyB.class, b.getId(), txnForAssert)); + + // successful insert using txn2 + assertNotNull(server.find(MnyB.class, c.getId(), txnForAssert)); + } + + @Test + public void basic() { + + MnyB a = new MnyB("a"); + MnyB b = new MnyB("b"); + MnyB c = new MnyB("c"); + + Transaction txn = Ebean.beginTransaction(); + try { + a.save(); + txn.commitAndContinue(); + + txn.setBatchMode(true); + b.save(); + logger.info("... pre commitAndContinue"); + txn.commitAndContinue(); + + c.save(); + txn.commit(); + + } finally { + txn.end(); + } + } + + @Test + @Transactional + public void runTransactional() { + + new MnyB("a100").save(); + new MnyB("a101").save(); + + Ebean.currentTransaction().commitAndContinue(); + + new MnyB("a200").save(); + new MnyB("a201").save(); + } + +} From fdb839f90e5cbee4faebcd5d788eaaf52f24dacc Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 11:20:12 +1200 Subject: [PATCH 56/65] #809 - Add test / example showing ... transaction.setPersistCascade(false) and transaction.commitAndContinue(); --- .../tests/transaction/TestBeanStateReset.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java b/src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java index 9825834ec..faeb64a13 100644 --- a/src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java +++ b/src/test/java/com/avaje/tests/transaction/TestBeanStateReset.java @@ -2,6 +2,7 @@ package com.avaje.tests.transaction; import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; +import com.avaje.ebean.Transaction; import com.avaje.tests.model.m2m.MnyB; import com.avaje.tests.model.m2m.MnyC; import org.avaje.ebeantest.LoggedSqlCollector; @@ -13,6 +14,7 @@ import javax.persistence.PersistenceException; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; public class TestBeanStateReset extends BaseTestCase { @@ -47,4 +49,51 @@ public class TestBeanStateReset extends BaseTestCase { } } + + @Test + public void alternativeVia_persistCascadeOff_with_commitAndContinue() { + + // setup to fail foreign key constraint when using cascade save + MnyC c = new MnyC(); + c.setId(Long.MAX_VALUE); + + MnyB b = new MnyB(); + b.getCs().add(c); + + Transaction transaction = Ebean.beginTransaction(); + + try { + // turn off cascade ... + transaction.setPersistCascade(false); + b.save(); + + // commit at this point + transaction.commitAndContinue(); + try { + + // turn on cascade ... such that the ManyToMany is persisted + transaction.setPersistCascade(true); + + // save b again which this time cascades to the ManyToMany + // but this fails due to FK on ManyToMany + b.save(); + + // we actually don't get here due to the FK error + transaction.commit(); + + } catch (PersistenceException e) { + // so we failed the second save but that is ok'ish + // we handle this exception knowing b got inserted and committed + // and that the inserts into the intersection table failed + logger.info("The ManyToMany intersection error: " + e.getMessage()); + } + } finally { + // performs a rollback as the commit at line:80 does not happen + transaction.end(); + } + + // assert our insert prior to the commitAndContinue succeeded + MnyB madeIt = Ebean.find(MnyB.class, b.getId()); + assertNotNull(madeIt); + } } From 6c182ecaa59ade4f8dfa2e8040b76894afaf2b5a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 12:14:58 +1200 Subject: [PATCH 57/65] #810 - ENH: Add transaction.isRollbackOnly() --- src/main/java/com/avaje/ebean/Transaction.java | 5 +++++ .../com/avaje/ebeaninternal/api/ScopedTransaction.java | 5 +++++ .../ebeaninternal/server/transaction/JdbcTransaction.java | 8 ++++++++ .../tests/transaction/TestTransactionRollbackOnly.java | 5 +++++ 4 files changed, 23 insertions(+) diff --git a/src/main/java/com/avaje/ebean/Transaction.java b/src/main/java/com/avaje/ebean/Transaction.java index 560a7278b..c05434b5c 100644 --- a/src/main/java/com/avaje/ebean/Transaction.java +++ b/src/main/java/com/avaje/ebean/Transaction.java @@ -118,6 +118,11 @@ public interface Transaction extends Closeable { */ void setRollbackOnly(); + /** + * Return true if the transaction is marked as rollback only. + */ + boolean isRollbackOnly(); + /** * If the transaction is active then perform rollback. Otherwise do nothing. */ diff --git a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java index 0d29f3aaf..2aa97a8ad 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java @@ -63,6 +63,11 @@ public class ScopedTransaction implements SpiTransaction { scopeTrans.setRollbackOnly(); } + @Override + public boolean isRollbackOnly() { + return transaction.isRollbackOnly(); + } + @Override public void end() throws PersistenceException { try { diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java index 80f2ef1d9..3185b4bfc 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java @@ -965,6 +965,14 @@ public class JdbcTransaction implements SpiTransaction { } } + /** + * Return true if the transaction is marked as rollback only. + */ + @Override + public boolean isRollbackOnly() { + return rollbackOnly; + } + /** * Mark the transaction as rollback only. */ diff --git a/src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java b/src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java index 5b536718c..5cfd3806d 100644 --- a/src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java +++ b/src/test/java/com/avaje/tests/transaction/TestTransactionRollbackOnly.java @@ -7,6 +7,8 @@ import com.avaje.tests.model.basic.EBasic; import org.junit.Test; import static org.assertj.core.api.StrictAssertions.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class TestTransactionRollbackOnly { @@ -30,7 +32,10 @@ public class TestTransactionRollbackOnly { Ebean.save(one); Transaction transaction = Ebean.currentTransaction(); + assertFalse(transaction.isRollbackOnly()); + transaction.setRollbackOnly(); + assertTrue(transaction.isRollbackOnly()); } @Test From 43afaf1344936e19b466a7f03e991c1fe5376278 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 13:01:42 +1200 Subject: [PATCH 58/65] #811 - ENH: Restore findIterate() as alternative to findEach / findEachWhile --- .../java/com/avaje/ebean/EbeanServer.java | 19 ++++++ .../java/com/avaje/ebean/ExpressionList.java | 7 ++ src/main/java/com/avaje/ebean/Query.java | 50 ++++++++++++++ .../java/com/avaje/ebean/QueryIterator.java | 67 +++++++++++++++++++ .../server/core/DefaultServer.java | 15 ++++- .../server/core/OrmQueryEngine.java | 2 +- .../server/core/OrmQueryRequest.java | 2 +- .../server/core/QueryIterator.java | 60 ----------------- .../server/core/SpiOrmQueryRequest.java | 1 + .../expression/DefaultExpressionList.java | 5 ++ .../server/expression/JunctionExpression.java | 6 ++ .../ebeaninternal/server/query/CQuery.java | 2 +- .../server/query/CQueryEngine.java | 2 +- .../server/query/CQueryIteratorSimple.java | 2 +- .../query/CQueryIteratorWithBuffer.java | 2 +- .../server/query/DefaultOrmQueryEngine.java | 3 +- .../server/querydefn/DefaultOrmQuery.java | 5 ++ .../ebeaninternal/api/TDSpiEbeanServer.java | 5 ++ .../tests/query/TestQueryFindIterate.java | 26 +++++++ 19 files changed, 211 insertions(+), 70 deletions(-) create mode 100644 src/main/java/com/avaje/ebean/QueryIterator.java delete mode 100644 src/main/java/com/avaje/ebeaninternal/server/core/QueryIterator.java diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index 6d13000b3..3490bd203 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -761,6 +761,25 @@ public interface EbeanServer { */
    List findIds(Query query, Transaction transaction); + /** + * Return a QueryIterator for the query. + *

    + * Generally using {@link #findEach(Query, QueryEachConsumer, Transaction)} or + * {@link #findEachWhile(Query, QueryEachWhileConsumer, Transaction)} is preferred + * to findIterate(). The reason is that those methods automatically take care of + * closing the queryIterator (and the underlying jdbc statement and resultSet). + *

    + *

    + * This is similar to findEach in that not all the result beans need to be held + * in memory at the same time and as such is good for processing large queries. + *

    + * + * @see Query#findIterate() + * @see Query#findEach(QueryEachConsumer) + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + QueryIterator findIterate(Query query, Transaction transaction); + /** * Execute the query visiting the each bean one at a time. *

    diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index 1937ee002..40db32065 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -147,6 +147,13 @@ public interface ExpressionList { */ int update(); + /** + * Execute the query iterating over the results. + * + * @see Query#findIterate() + */ + QueryIterator findIterate(); + /** * Execute the query process the beans one at a time. * diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 0c60ecd23..47b4661cc 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -544,6 +544,46 @@ public interface Query { */ List findIds(); + /** + * Execute the query iterating over the results. + *

    + * Note that findIterate (and findEach and findEachWhile) uses a "per graph" + * persistence context scope and adjusts jdbc fetch buffer size for large + * queries. As such it is better to use findList for small queries. + *

    + *

    + * Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()} + * when you have finished iterating the results (typically in a finally block). + *

    + *

    + * findEach() and findEachWhile() are preferred to findIterate() as they ensure + * the jdbc statement and resultSet are closed at the end of the iteration. + *

    + *

    + * This query will execute against the EbeanServer that was used to create it. + *

    + *
    {@code
    +   *
    +   *  Query query =
    +   *    ebeanServer.find(Customer.class)
    +   *     .where().eq("status", Status.NEW)
    +   *     .order().asc("id");
    +   *
    +   *  QueryIterator it = query.findIterate();
    +   *  try {
    +   *    while (it.hasNext()) {
    +   *      Customer customer = it.next();
    +   *      // do something with customer ...
    +   *    }
    +   *  } finally {
    +   *    // close the underlying resources
    +   *    it.close();
    +   *  }
    +   *
    +   * }
    + */ + QueryIterator findIterate(); + /** * Execute the query processing the beans one at a time. *

    @@ -552,6 +592,11 @@ public interface Query { * (unlike #findList #findSet etc) *

    *

    + * Note that findEach (and findEachWhile and findIterate) uses a "per graph" + * persistence context scope and adjusts jdbc fetch buffer size for large + * queries. As such it is better to use findList for small queries. + *

    + *

    * Note that internally Ebean can inform the JDBC driver that it is expecting larger * resultSet and specifically for MySQL this hint is required to stop it's JDBC driver * from buffering the entire resultSet. As such, for smaller resultSets findList() is @@ -588,6 +633,11 @@ public interface Query { * Execute the query using callbacks to a visitor to process the resulting * beans one at a time. *

    + * Note that findEachWhile (and findEach and findIterate) uses a "per graph" + * persistence context scope and adjusts jdbc fetch buffer size for large + * queries. As such it is better to use findList for small queries. + *

    + *

    * This method is functionally equivalent to findIterate() but instead of using an * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use * with Java8 closures. diff --git a/src/main/java/com/avaje/ebean/QueryIterator.java b/src/main/java/com/avaje/ebean/QueryIterator.java new file mode 100644 index 000000000..23bfaea55 --- /dev/null +++ b/src/main/java/com/avaje/ebean/QueryIterator.java @@ -0,0 +1,67 @@ +package com.avaje.ebean; + +import java.util.Iterator; + +/** + * Used to provide iteration over query results. + *

    + * This can be used when you want to process a very large number of results and + * means that you don't have to hold all the results in memory at once (unlike + * findList(), findSet() etc where all the beans are held in the List or Set + * etc). + *

    + *

    + * Note that findIterate (and findEach and findEachWhile) uses a "per graph" + * persistence context scope and adjusts jdbc fetch buffer size for large + * queries. As such it is better to use findList for small queries. + *

    + *

    + * Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()} + * when you have finished iterating the results (typically in a finally block). + *

    + * + *
    {@code
    + * 
    + *  Query query = server.find(Customer.class)
    + *     .where().gt("id", 0)
    + *     .orderBy("id")
    + *     .setMaxRows(2);
    + *
    + *  QueryIterator it = query.findIterate();
    + *  try {
    + *    while (it.hasNext()) {
    + *      Customer customer = it.next();
    + *      // do something with customer ...
    + *    }
    + *  } finally {
    + *    // close the underlying resources
    + *    it.close();
    + *  }
    + *
    + * }
    + * + * @param + * the type of entity bean in the iteration + */ +public interface QueryIterator extends Iterator, java.io.Closeable { + + /** + * Returns true if the iteration has more elements. + */ + boolean hasNext(); + + /** + * Returns the next element in the iteration. + */ + T next(); + + /** + * Remove is not allowed. + */ + void remove(); + + /** + * Close the underlying resources held by this iterator. + */ + void close(); +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index 7c3e76a57..a87e07960 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -71,10 +71,8 @@ import javax.persistence.NonUniqueResultException; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; import javax.sql.DataSource; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -1304,6 +1302,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return new LimitOffsetPagedList(this, spiQuery); } + public QueryIterator findIterate(Query query, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, t); + try { + request.initTransIfRequired(); + return request.findIterate(); + + } catch (RuntimeException ex) { + request.endTransIfRequired(); + throw ex; + } + } + public void findEach(Query query, QueryEachConsumer consumer, Transaction t) { SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, t); diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java index c38ce79ca..83acce984 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java @@ -1,8 +1,8 @@ package com.avaje.ebeaninternal.server.core; +import com.avaje.ebean.QueryIterator; import com.avaje.ebean.Version; import com.avaje.ebean.bean.BeanCollection; -import com.avaje.ebeaninternal.api.BeanIdList; import java.util.List; diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java index c9bf91f82..5b1a74340 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java @@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.core; import com.avaje.ebean.PersistenceContextScope; import com.avaje.ebean.QueryEachConsumer; import com.avaje.ebean.QueryEachWhileConsumer; +import com.avaje.ebean.QueryIterator; import com.avaje.ebean.RawSql; import com.avaje.ebean.Version; import com.avaje.ebean.bean.BeanCollection; @@ -12,7 +13,6 @@ import com.avaje.ebean.event.BeanFindController; import com.avaje.ebean.event.BeanQueryAdapter; import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebean.text.json.JsonReadOptions; -import com.avaje.ebeaninternal.api.BeanIdList; import com.avaje.ebeaninternal.api.CQueryPlanKey; import com.avaje.ebeaninternal.api.HashQuery; import com.avaje.ebeaninternal.api.LoadContext; diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/QueryIterator.java b/src/main/java/com/avaje/ebeaninternal/server/core/QueryIterator.java deleted file mode 100644 index 148a7d8c1..000000000 --- a/src/main/java/com/avaje/ebeaninternal/server/core/QueryIterator.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.avaje.ebeaninternal.server.core; - -import java.util.Iterator; - -/** - * Used to provide iteration over query results. - *

    - * This can be used when you want to process a very large number of results and - * means that you don't have to hold all the results in memory at once (unlike - * findList(), findSet() etc where all the beans are held in the List or Set - * etc). - *

    - * - *
    - * 
    - * Query<Customer> query = server.find(Customer.class)
    - *     .fetch("contacts", new FetchConfig().query(2))
    - *     .where().gt("id", 0)
    - *     .orderBy("id")
    - *     .setMaxRows(2);
    - * 
    - * QueryIterator<Customer> it = query.findIterate();
    - * try {
    - *   while (it.hasNext()) {
    - *     Customer customer = it.next();
    - *     // do something with customer...
    - *   }
    - * } finally {
    - *   // close the associated resources
    - *   it.close();
    - * }
    - * 
    - * - * @author rbygrave - * - * @param - * the type of entity bean in the iteration - */ -public interface QueryIterator extends Iterator, java.io.Closeable { - - /** - * Returns true if the iteration has more elements. - */ - boolean hasNext(); - - /** - * Returns the next element in the iteration. - */ - T next(); - - /** - * Remove is not allowed. - */ - void remove(); - - /** - * Close the underlying resources held by this iterator. - */ - void close(); -} diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java index b7ed67df4..7c68e63c8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.core; import com.avaje.ebean.QueryEachConsumer; import com.avaje.ebean.QueryEachWhileConsumer; +import com.avaje.ebean.QueryIterator; import com.avaje.ebean.Version; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebeaninternal.api.SpiQuery; diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index d5840c3a0..a62f9a7bd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -358,6 +358,11 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findIds(); } + @Override + public QueryIterator findIterate() { + return query.findIterate(); + } + @Override public void findEach(QueryEachConsumer consumer) { query.findEach(consumer); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 9132b0807..1df86c1e7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -12,6 +12,7 @@ import com.avaje.ebean.PagedList; import com.avaje.ebean.Query; import com.avaje.ebean.QueryEachConsumer; import com.avaje.ebean.QueryEachWhileConsumer; +import com.avaje.ebean.QueryIterator; import com.avaje.ebean.Version; import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebean.search.Match; @@ -375,6 +376,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.findIds(); } + @Override + public QueryIterator findIterate() { + return exprList.findIterate(); + } + @Override public void findEach(QueryEachConsumer consumer) { exprList.findEach(consumer); diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java index ca37d7976..d3e1121bd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java @@ -1,6 +1,6 @@ package com.avaje.ebeaninternal.server.query; -import com.avaje.ebeaninternal.server.core.QueryIterator; +import com.avaje.ebean.QueryIterator; import com.avaje.ebean.Version; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.EntityBean; diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java index bcf3d5da5..49d8625f9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java @@ -10,7 +10,7 @@ import com.avaje.ebean.config.dbplatform.DatabasePlatform; import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeaninternal.server.core.DiffHelp; import com.avaje.ebeaninternal.server.core.OrmQueryRequest; -import com.avaje.ebeaninternal.server.core.QueryIterator; +import com.avaje.ebean.QueryIterator; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.lib.util.Str; import com.avaje.ebeaninternal.server.persist.Binder; diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java index 2fe591939..88dba323a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java @@ -4,7 +4,7 @@ import java.sql.SQLException; import javax.persistence.PersistenceException; -import com.avaje.ebeaninternal.server.core.QueryIterator; +import com.avaje.ebean.QueryIterator; import com.avaje.ebeaninternal.server.core.OrmQueryRequest; /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java index fc042d264..163fdfc2f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import javax.persistence.PersistenceException; -import com.avaje.ebeaninternal.server.core.QueryIterator; +import com.avaje.ebean.QueryIterator; import com.avaje.ebeaninternal.server.core.OrmQueryRequest; /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java index 5a0a0112b..493d7030b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultOrmQueryEngine.java @@ -1,11 +1,10 @@ package com.avaje.ebeaninternal.server.query; -import com.avaje.ebeaninternal.server.core.QueryIterator; +import com.avaje.ebean.QueryIterator; import com.avaje.ebean.Version; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.event.BeanFindController; -import com.avaje.ebeaninternal.api.BeanIdList; import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeaninternal.api.SpiTransaction; import com.avaje.ebeaninternal.server.core.OrmQueryEngine; diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 2adcf19ad..370fd8bc8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1114,6 +1114,11 @@ public class DefaultOrmQuery implements SpiQuery { server.findEach(this, consumer, null); } + @Override + public QueryIterator findIterate() { + return server.findIterate(this, null); + } + @Override public List> findVersions() { this.temporalMode = TemporalMode.VERSIONS; diff --git a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java index e7ea6a3bb..a05d5fc98 100644 --- a/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/com/avaje/ebeaninternal/api/TDSpiEbeanServer.java @@ -470,6 +470,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return null; } + @Override + public QueryIterator findIterate(Query query, Transaction transaction) { + return null; + } + @Override public void findEach(Query query, QueryEachConsumer consumer, Transaction transaction) { diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindIterate.java b/src/test/java/com/avaje/tests/query/TestQueryFindIterate.java index f03b6da6c..67b6bc466 100644 --- a/src/test/java/com/avaje/tests/query/TestQueryFindIterate.java +++ b/src/test/java/com/avaje/tests/query/TestQueryFindIterate.java @@ -27,6 +27,32 @@ public class TestQueryFindIterate extends BaseTestCase { EbeanServer server = Ebean.getServer(null); + Query query = server.find(Customer.class) + .setMaxRows(2); + + final AtomicInteger count = new AtomicInteger(); + + QueryIterator it = query.findIterate(); + try { + while (it.hasNext()) { + Customer customer = it.next(); + customer.getName(); + count.incrementAndGet(); + } + } finally { + it.close(); + } + + assertEquals(2, count.get()); + } + + @Test + public void findEach() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + Query query = server.find(Customer.class) .setAutoTune(false) //.fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") From 7f42d045ac7024cf0ae889c5f2f05b1550c7fb0a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 13:29:28 +1200 Subject: [PATCH 59/65] No effective change - javadoc typo --- src/main/java/com/avaje/ebean/Model.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java index 4f5b7418c..f03e52706 100644 --- a/src/main/java/com/avaje/ebean/Model.java +++ b/src/main/java/com/avaje/ebean/Model.java @@ -495,7 +495,7 @@ public abstract class Model { /** * Return typically a different EbeanServer to the default. *

    - * This is equivilent to {@link Ebean#getServer(String)} + * This is equivalent to {@link Ebean#getServer(String)} * * @param server * The name of the EbeanServer. If this is null then the default EbeanServer is From c427009b93b7647c1607077b3905b7f81dce4fc3 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 13:47:32 +1200 Subject: [PATCH 60/65] #812 - Remove deprecated includeSoftDeletes() ... migrate to setIncludeSoftDeletes() --- src/main/java/com/avaje/ebean/ExpressionList.java | 6 ------ .../server/expression/DefaultExpressionList.java | 5 ----- .../server/expression/JunctionExpression.java | 8 ++------ 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index 40db32065..4f8d38d29 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -116,12 +116,6 @@ public interface ExpressionList { */ Query asDraft(); - /** - * Deprecated in favour of setIncludeSoftDeletes(). - */ - @Deprecated - Query includeSoftDeletes(); - /** * Execute the query including soft deleted rows. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java index a62f9a7bd..9c3eb64d1 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/DefaultExpressionList.java @@ -253,11 +253,6 @@ public class DefaultExpressionList implements SpiExpressionList { return query.asDraft(); } - @Override - public Query includeSoftDeletes() { - return setIncludeSoftDeletes(); - } - @Override public Query setIncludeSoftDeletes() { return query.setIncludeSoftDeletes(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 1df86c1e7..1788ce7cb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -63,6 +63,7 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression * This is expected to only used after expressions are built via query language parsing. *

    */ + @SuppressWarnings("unchecked") public void simplify() { exprList.simplifyEntries(); @@ -326,11 +327,6 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.asDraft(); } - @Override - public Query includeSoftDeletes() { - return setIncludeSoftDeletes(); - } - @Override public Query setIncludeSoftDeletes() { return exprList.setIncludeSoftDeletes(); @@ -372,7 +368,7 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression } @Override - public List findIds() { + public List findIds() { return exprList.findIds(); } From 0a830841c4de422c8ad92baae8428b99dac83e69 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 13:52:09 +1200 Subject: [PATCH 61/65] Bump pom to 8.2.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 78d4fb594..305646f9c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebean ebean - 8.1.2-SNAPSHOT + 8.2.1-SNAPSHOT jar ebean From 2cc4c2c265239cc6f39f80db7e76cbbb46e9a0c9 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 13:53:03 +1200 Subject: [PATCH 62/65] [maven-release-plugin] prepare release ebean-8.2.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 305646f9c..2b88bc39c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebean ebean - 8.2.1-SNAPSHOT + 8.2.1 jar ebean @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - HEAD + ebean-8.2.1 From d722d340728b6cd2c9e89849dabf239128663bd6 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 5 Aug 2016 13:53:23 +1200 Subject: [PATCH 63/65] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2b88bc39c..0802002ba 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebean ebean - 8.2.1 + 8.2.2-SNAPSHOT jar ebean @@ -37,7 +37,7 @@ scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git - ebean-8.2.1 + HEAD From ce045ca0fe1e5b2f0da0219a363c6b836f201709 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 11 Aug 2016 20:22:35 +1200 Subject: [PATCH 64/65] No effective change - remove unused methods (from ImportedId) --- .../server/deploy/id/ImportedId.java | 10 ------ .../server/deploy/id/ImportedIdEmbedded.java | 33 ------------------- .../server/deploy/id/ImportedIdSimple.java | 19 ----------- 3 files changed, 62 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedId.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedId.java index a4c56587a..77b79de30 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedId.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedId.java @@ -22,11 +22,6 @@ public interface ImportedId { */ boolean isScalar(); - /** - * Return the logical property name. - */ - String getLogicalName(); - /** * For scalar id return the related single db column. *

    @@ -46,11 +41,6 @@ public interface ImportedId { */ void dmlAppend(GenerateDmlRequest request); - /** - * Append to the DML statement to the where clause. - */ - void dmlWhere(GenerateDmlRequest request, EntityBean bean); - /** * Bind the value from the bean. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java index fff0d126c..6a75753c0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java @@ -46,11 +46,6 @@ public class ImportedIdEmbedded implements ImportedId { return false; } - public String getLogicalName() { - return owner.getName() + "." + foreignAssocOne.getName(); - } - - public String getDbColumn() { return null; } @@ -68,34 +63,6 @@ public class ImportedIdEmbedded implements ImportedId { } } - public void dmlWhere(GenerateDmlRequest request, EntityBean bean) { - - Object embeddedId = null; - if (bean != null) { - embeddedId = foreignAssocOne.getValue(bean); - } - - if (embeddedId == null) { - for (int i = 0; i < imported.length; i++) { - if (imported[i].owner.isDbUpdatable()) { - request.appendColumnIsNull(imported[i].localDbColumn); - } - } - } else { - EntityBean embedded = (EntityBean) embeddedId; - for (int i = 0; i < imported.length; i++) { - if (imported[i].owner.isDbUpdatable()) { - Object value = imported[i].foreignProperty.getValue(embedded); - if (value == null) { - request.appendColumnIsNull(imported[i].localDbColumn); - } else { - request.appendColumn(imported[i].localDbColumn); - } - } - } - } - } - public Object bind(BindableRequest request, EntityBean bean) throws SQLException { Object embeddedId = null; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdSimple.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdSimple.java index d706995fc..4241f37d7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdSimple.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/id/ImportedIdSimple.java @@ -82,10 +82,6 @@ public final class ImportedIdSimple implements ImportedId, Comparable Date: Fri, 12 Aug 2016 17:20:29 +0800 Subject: [PATCH 65/65] Update README.md and pom.xml for artifactId change --- README.md | 10 +++++----- pom.xml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7f6f03932..022e7794c 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web ## Maven cental links: -[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm") +[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean") -[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm") +[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects") ## Current versions -* [![Maven Central : avaje-ebeanorm](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm -* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent -* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer +* [![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean +* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent +* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin diff --git a/pom.xml b/pom.xml index 0802002ba..dbd0ea83d 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ - scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git + scm:git:https://github.com/ebean-orm/ebean.git HEAD