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
-* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
-* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
-* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
+* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
+* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
+* [](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 ec2540282..dbd0ea83d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,12 +7,12 @@
diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java
index 3392334a6..3490bd203 100644
--- a/src/main/java/com/avaje/ebean/EbeanServer.java
+++ b/src/main/java/com/avaje/ebean/EbeanServer.java
@@ -739,20 +739,46 @@ public interface EbeanServer {
{@code
+ *
+ * List names =
+ * Ebean.find(Customer.class)
+ * .select("name")
+ * .orderBy().asc("name")
+ * .findSingleAttributeList();
+ *
+ * }
+ *
+ * {@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
*/
- {@code
*
* // create an example bean and set the properties
@@ -627,26 +669,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();
*
* }
@@ -748,7 +790,7 @@ public interface ExpressionList- * 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
*
* }
*
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
*/
+ Future* Example: Create the query using the API. *
- * + **
{@code
*
- * List orderList =
+ * List orderList =
* ebeanServer.find(Order.class)
* .fetch("customer")
* .fetch("details")
@@ -26,46 +26,40 @@ import java.util.Set;
* .orderBy("customer.id, id desc")
* .setMaxRows(50)
* .findList();
- *
+ *
* ...
* }
- *
* * Example: The same query using the query language *
- * *{@code
*
- * String oql =
- * " find order "
+ * String oql =
* +" 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();
* ...
* }
- *
* * Ebean has built in support for "AutoTune". This is a mechanism where a query @@ -82,7 +76,6 @@ import java.util.Set; * to a remote client or where there is some requirement for "Read Consistency" * guarantees. *
- * ** Partial Objects @@ -101,36 +94,25 @@ 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} ) ] ]
+ * [ 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. @@ -161,52 +143,34 @@ 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)
+ *
+ * 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 * details and related product. Note that customer and product objects will be @@ -215,63 +179,16 @@ import java.util.Set; * objects (associated with each order detail) will have their id, sku and name * populated. *
- * *{@code
- * find order
+ *
* fetch customer (name)
* fetch customer.shippingAddress
* fetch details
* fetch details.product (sku, name)
+ *
* }
- *
- * - * 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. - *
- *- * 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. - *
- * The full WHERE clause is constructed by appending together - *
- * The above is the order that these are clauses are appended to give the full - * WHERE clause. - *
- *- * 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- * 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 @@ -325,7 +242,7 @@ public interface Query- * 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
*
* List customers =
@@ -412,42 +330,33 @@ 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- * 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")
- *
+ *
* // ... 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. + * If columns is null or "*" then all columns/properties for that path are fetched. *
- * *{@code
*
* // fetch customers (their id, name and status)
@@ -458,19 +367,66 @@ 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 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+ * 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+ * This is the same as: + *
+ *{@code
+ *
+ * fetch(path, fetchProperties, new FetchConfig().lazy())
+ *
+ * }
+ * + * The reason for using fetchLazy() is to either: + *
+ *{@code
*
* // fetch customers (their id, name and status)
@@ -481,13 +437,17 @@ public interface Query {
* .findList();
*
* }
+ *
+ * @param path the property path we wish to fetch eagerly.
*/
- Query- * 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
*
@@ -500,16 +460,59 @@ 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+ * 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+ * This is the same as: + *
+ *{@code
+ *
+ * fetch(path, new FetchConfig().lazy())
+ *
+ * }
+ * + * The reason for using fetchLazy() is to either: + *
+ *{@code
*
* // fetch customers (their id, name and status)
@@ -536,10 +539,50 @@ public interface Query {
*
* This query will execute against the EbeanServer that was used to create it.
*
- *
+ *
* @see EbeanServer#findIds(Query, Transaction)
*/
- List findIds();
+ 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.
@@ -549,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
@@ -564,7 +612,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 +625,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);
@@ -587,12 +633,15 @@ 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.
*
-
- *
* {@code
*
* ebeanServer.find(Customer.class)
@@ -611,8 +660,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 +669,6 @@ public interface Query {
*
* This query will execute against the EbeanServer that was used to create it.
*
- *
* {@code
*
* List customers =
@@ -640,7 +687,6 @@ public interface Query {
*
* This query will execute against the EbeanServer that was used to create it.
*
- *
* {@code
*
* Set customers =
@@ -663,24 +709,50 @@ 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, Product> map =
+ * Map map =
* ebeanServer.find(Product.class)
* .setMapKey("sku")
* .findMap();
*
* }
- *
+ *
* @see EbeanServer#findMap(Query, Transaction)
*/
- Map, T> findMap();
+ Map findMap();
/**
- * Return a typed map specifying the key property and type.
+ * 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
*/
- Map findMap(String keyProperty, Class keyType);
+ List findSingleAttributeList();
/**
* Execute the query returning either a single bean or null (if no matching
@@ -693,7 +765,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 +774,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 +800,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 +814,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 +843,15 @@ 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 +861,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 +888,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 +914,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 +935,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 +957,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 +982,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 +1004,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 +1020,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 +1030,9 @@ public interface Query {
* .findList();
*
* }
- *
- * @see Expr
+ *
* @return The ExpressionList for adding expressions to.
+ * @see Expr
*/
ExpressionList where();
@@ -984,9 +1067,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 +1077,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 +1100,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 +1116,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 +1229,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 +1239,10 @@ public interface Query {
*
* If no property is set then the id property is used.
*
- *
* {@code
*
* // Assuming sku is unique for products...
- *
+ *
* Map,Product> productMap =
* ebeanServer.find(Product.class)
* // use sku for keys...
@@ -1174,9 +1250,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 +1278,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 +1301,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);
@@ -1238,6 +1312,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);
@@ -1260,7 +1344,7 @@ public interface Query {
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
-
+
/**
* Set root table alias.
*/
@@ -1274,7 +1358,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/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/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/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/ebean/Transaction.java b/src/main/java/com/avaje/ebean/Transaction.java
index cd2db3004..c05434b5c 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;
@@ -74,6 +113,16 @@ public interface Transaction extends Closeable {
*/
void rollback(Throwable e) throws PersistenceException;
+ /**
+ * Mark the transaction for rollback only.
+ */
+ 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.
*/
@@ -417,9 +466,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/ebean/bean/EntityBeanIntercept.java b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java
index 24462e614..22d68e0e4 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.
*/
@@ -325,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.
*
@@ -832,19 +856,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/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/config/dbplatform/DatabasePlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java
index edf934518..cd243e4e4 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.
@@ -34,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/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();
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);
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/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/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;
}
/**
diff --git a/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java b/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java
index ad5863311..0caab1800 100644
--- a/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java
+++ b/src/main/java/com/avaje/ebeaninternal/api/ManyWhereJoins.java
@@ -132,15 +132,11 @@ public class ManyWhereJoins implements Serializable {
formulaProperties.append(propertyName);
}
- public boolean isHasMany() {
- return formulaWithJoin || !joins.isEmpty();
- }
-
/**
- * 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/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..2aa97a8ad 100644
--- a/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java
+++ b/src/main/java/com/avaje/ebeaninternal/api/ScopedTransaction.java
@@ -29,9 +29,13 @@ public class ScopedTransaction implements SpiTransaction {
public ScopedTransaction(ScopeTrans scopeTrans) {
this.scopeTrans = scopeTrans;
- this.transaction =scopeTrans.getTransaction();
+ this.transaction = scopeTrans.getTransaction();
}
+ @Override
+ public void commitAndContinue() throws RollbackException {
+ transaction.commitAndContinue();
+ }
@Override
public void commit() throws RollbackException {
@@ -49,6 +53,21 @@ public class ScopedTransaction implements SpiTransaction {
scopeTrans.rollback(e);
}
+ @Override
+ public void rollbackIfActive() {
+ transaction.rollbackIfActive();
+ }
+
+ @Override
+ public void setRollbackOnly() {
+ 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/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 8b4ebffa0..b0254617b 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.
*/
@@ -246,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.
*/
@@ -341,6 +331,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.
*/
@@ -593,9 +601,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/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/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/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/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/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
index 5bc59014d..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;
@@ -1134,30 +1132,52 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
@SuppressWarnings({ "unchecked", "rawtypes" })
- public Map, T> 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, T>) result;
+ return (Map) result;
}
try {
request.initTransIfRequired();
- return (Map, T>) request.findMap();
+ return (Map) request.findMap();
} finally {
request.endTransIfRequired();
}
}
- public int findRowCount(Query query, Transaction t) {
+ @Override
+ @SuppressWarnings("unchecked")
+ 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();
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);
@@ -1170,16 +1190,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();
@@ -1213,7 +1231,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,17 +1246,15 @@ 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();
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);
@@ -1286,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/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/OrmQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryEngine.java
index 02464b5bc..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;
@@ -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);
/**
@@ -36,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 0aa5a472b..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;
@@ -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) {
@@ -373,6 +372,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/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
index afd86bfa6..fa954bcff 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);
@@ -803,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/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 b5f22603a..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;
@@ -70,7 +71,7 @@ public interface SpiOrmQueryRequest extends DocQueryRequest {
/**
* Execute the find ids query.
*/
- List findIds();
+ List findIds();
/**
* Execute the find returning a QueryIterator and visitor pattern.
@@ -107,6 +108,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/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/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/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/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