Compare commits

..
Author SHA1 Message Date
Robin Bygrave 2cc4c2c265 [maven-release-plugin] prepare release ebean-8.2.1 2016-08-05 13:53:03 +12:00
Robin Bygrave 0a830841c4 Bump pom to 8.2.1-SNAPSHOT 2016-08-05 13:52:09 +12:00
Robin Bygrave c427009b93 #812 - Remove deprecated includeSoftDeletes() ... migrate to setIncludeSoftDeletes() 2016-08-05 13:47:32 +12:00
Robin Bygrave 7f42d045ac No effective change - javadoc typo 2016-08-05 13:29:28 +12:00
Robin Bygrave 43afaf1344 #811 - ENH: Restore findIterate() as alternative to findEach / findEachWhile 2016-08-05 13:01:42 +12:00
Robin Bygrave 6c182ecaa5 #810 - ENH: Add transaction.isRollbackOnly() 2016-08-05 12:14:58 +12:00
Robin Bygrave fdb839f90e #809 - Add test / example showing ... transaction.setPersistCascade(false) and transaction.commitAndContinue(); 2016-08-05 11:20:12 +12:00
Robin Bygrave 16be213faf #808 - ENH: Add Transaction commitAndContinue() ... 2016-08-05 10:39:17 +12:00
Robin Bygrave 3344f0ddb0 Refactor - remove unused method JdbcTransaction.notifyQueryOnly(). 2016-08-04 23:25:50 +12:00
Robin Bygrave 479ac38537 #807 - Deprecate TransactionEventListener ... migrate to TransactionCallback 2016-08-04 23:17:57 +12:00
Robin Bygrave e30ad80f5f #806 - Deprecate OnQueryOnly.CLOSE ... 2016-08-04 23:02:26 +12:00
Robin Bygrave 08e46d6bf3 #805 - ENH: Add BeanState.resetForInsert() ... This resets bean state such that a save() results in an insert 2016-08-04 22:49:07 +12:00
Robin Bygrave 876476fdc1 #804 - Remove API - findMap(property, type) ... migrate to query.setMapKey() 2016-08-04 20:30:18 +12:00
Robin Bygrave 81de83a6e7 #803 - Fix generics on findMap() to ... <K> Map<K, T> findMap(); 2016-08-04 20:23:11 +12:00
Robin Bygrave b5b221ffb1 No effective change - remove unused constructors 2016-08-04 17:32:18 +12:00
Robin Bygrave 3c6eab6c85 #802 - Find generics on findIds() - refactor internals of find ids to use find single attribute 2016-08-04 17:28:41 +12:00
Robin Bygrave 1be30f1671 #125 - ENH: Add support for query returning a List of single Attribute type 2016-08-04 16:41:50 +12:00
Robin Bygrave 9a5cb242ce No effective change - remove commented out line from pom 2016-08-04 13:56:09 +12:00
Robin Bygrave ea69cae4a3 [maven-release-plugin] prepare for next development iteration 2016-08-03 16:24:43 +12:00
Robin Bygrave 629fb7a433 [maven-release-plugin] prepare release ebean-8.1.1 2016-08-03 16:24:23 +12:00
Robin Bygrave 4ff10da739 #801 - Change maven groupId ... to org.avaje.ebean, artifactId to ebean 2016-08-03 16:23:26 +12:00
Robin Bygrave 9472592a50 [maven-release-plugin] prepare for next development iteration 2016-08-03 00:40:37 +12:00
Robin Bygrave f42682ca90 [maven-release-plugin] prepare release avaje-ebeanorm-8.1.1 2016-08-03 00:40:18 +12:00
Robin Bygrave 5dc296e644 #798 - Add @Transactional based test 2016-08-03 00:38:58 +12:00
Robin Bygrave 380660913f No effective change - javadoc update on Query 2016-08-02 23:42:00 +12:00
Robin Bygrave d08ac6973e #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:33:02 +12:00
Robin Bygrave 9d23c1d56e #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:30:26 +12:00
Robin Bygrave b5d6c5f70b #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:30:04 +12:00
Robin Bygrave 3657d05774 #798 - ENH: Add support for transparent full JDBC batch. Via enhancement agent 8.1.1 ... 2016-08-02 21:41:13 +12:00
Robin Bygrave 2de8ae777d Merge branch 'wip/getterCallback' 2016-08-02 21:34:41 +12:00
Robin Bygrave 16950a5641 [maven-release-plugin] prepare for next development iteration 2016-08-02 21:32:08 +12:00
Robin Bygrave ad992d07ce [maven-release-plugin] prepare release avaje-ebeanorm-7.21.2 2016-08-02 21:31:47 +12:00
Robin Bygrave cbcec8f5ea No effective change - tidy 2016-08-02 20:32:59 +12:00
Robin Bygrave 6e2148d20b #799 - Query.fetch(path) when converted to query join default to batchSize 10 rather than 100 2016-08-02 20:19:38 +12:00
Robin Bygrave ca1c0a08f3 No effective change - remove whitespace on DLoadBeanContext 2016-08-02 20:14:46 +12:00
Robin Bygrave baa6fc355e No effective change - javadoc update on FetchConfig 2016-08-02 20:14:07 +12:00
Robin Bygrave dacdc26902 #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. 2016-08-02 16:16:34 +12:00
Robin Bygrave 48edf64013 No effective change - typo in javadoc 2016-08-02 11:10:19 +12:00
Robin Bygrave e2ee6e8e98 No effective change - update tests with EBasicVer new constructor 2016-08-02 11:06:09 +12:00
Robin Bygrave e6e6a28245 No effective change - tidy asserts on TestQueryDistinct (AssertJ string contains etc) 2016-08-01 22:53:47 +12:00
Rob BygraveandGitHub 82a695a98a Merge pull request #797 from backslash47/master
Add check for distinct query when adding id attribute to order clause in paging query
2016-08-01 22:47:34 +12:00
Matus Zamborsky cdad31bd8a Added test for distinct paging query 2016-08-01 12:20:50 +02:00
Matus Zamborsky 4d16cf9caa Add check for distinct query when adding id attribute to order clause in paging query 2016-08-01 10:13:05 +02:00
Robin Bygrave 84a86cad0e #794 - Refactor - tidy code, remove unused mimetypes properties 2016-07-31 23:34:55 +12:00
Robin Bygrave dfdf87fa2d #794 - Refactor - tidy code, javadoc tidy 2016-07-31 23:33:29 +12:00
Robin Bygrave ee0615caec #794 - Refactor - tidy code, use uppercase L for Long literal 2016-07-31 23:33:07 +12:00
Robin Bygrave 79b8395f8f #794 - Refactor - tidy code, simplify if 2016-07-31 23:32:37 +12:00
Robin Bygrave 87c479cd95 #794 - Refactor - tidy code, remove unused imports 2016-07-31 23:24:30 +12:00
Robin Bygrave abbdda810a #794 - Refactor - tidy code, remove unused method arguments 2016-07-31 23:23:57 +12:00
Robin Bygrave e621900de9 #794 - Refactor - tidy code, remove unused method arguments 2016-07-31 23:23:43 +12:00
Robin Bygrave 76b33511e1 #793 - com.avaje.ebean.event.changelog.BeanChange not keeping passed id value 2016-07-31 23:14:08 +12:00
Robin Bygrave 77deab5cf0 #792 - Change Logging Rollback message on org.avaje.ebean.TXN from INFO level to DEBUG level 2016-07-31 22:52:48 +12:00
Robin Bygrave 4a9f8cef0e No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name 2016-07-31 22:49:10 +12:00
Robin Bygrave 4d1340c16c No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name 2016-07-31 22:46:07 +12:00
Robin Bygrave 74c6c71301 [maven-release-plugin] prepare for next development iteration 2016-07-31 21:28:17 +12:00
Robin Bygrave 0f0028eb1f [maven-release-plugin] prepare release avaje-ebeanorm-7.21.1 2016-07-31 21:27:58 +12:00
Robin Bygrave b4a1d52067 #791 - ENH: Add transaction.setRollbackOnly() ... (and Ebean.setRollbackOnly()) 2016-07-31 21:24:31 +12:00
Robin Bygrave d82148248c No effective change - javadoc tidy 2016-07-31 20:55:34 +12:00
Robin Bygrave dc7c854432 #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() 2016-07-31 19:06:21 +12:00
Robin Bygrave 7c83010df1 #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() 2016-07-31 16:39:23 +12:00
Robin Bygrave ed41e58073 Bump pom version to 7.21.1-SNAPSHOT 2016-07-31 16:01:00 +12:00
Robin Bygrave 5bab9eb648 #790 - DB Migration with multiple platforms (and no maven H2 dependency) gives: java.lang.NoClassDefFoundError: org/h2/api/Trigger 2016-07-31 15:59:54 +12:00
Robin Bygrave 5ce8eb6046 No effective change - remove unused methods 2016-07-31 15:02:05 +12:00
Robin Bygrave 56fee2ea9b #789 - findCount() ... with where raw(...) expression that includes a "many" produces incorrect SQL 2016-07-31 14:57:12 +12:00
Robin Bygrave 780ee7c7c0 [maven-release-plugin] prepare for next development iteration 2016-07-25 23:37:18 +12:00
Robin Bygrave 2bac7bf84d [maven-release-plugin] prepare release avaje-ebeanorm-7.20.1 2016-07-25 23:36:58 +12:00
Robin Bygrave 499862438d Bump pom to 7.20.1-SNAPSHOT 2016-07-25 23:36:12 +12:00
Robin Bygrave 4ad0b7cf66 #786 - Bump avaje-dbmigration to 1.2.1 ... which uses autoCommit true when running drop-all ddl 2016-07-25 23:34:17 +12:00
Robin Bygrave 6108ef484b #782 - History Many-To-Many Lazy-Loads fail 2016-07-25 23:31:02 +12:00
Robin Bygrave b763f4c875 #783 - HistoryExclude Many-to-Many Query-Generation Error 2016-07-25 23:29:33 +12:00
Robin Bygrave ca7285b2ad #783 - tests for ... HistoryExclude Many-to-Many Query-Generation Error 2016-07-25 23:28:45 +12:00
Robin Bygrave 75b639bc15 #782 - tests for ... History Many-To-Many Lazy-Loads fail 2016-07-25 23:22:33 +12:00
Robin Bygrave 1a7c4dac3f #1 - Change DdlGenerator.runScript() so that it uses connection.setAutoCommit(true) for drop ddl - when expectErrors is true 2016-07-25 23:03:00 +12:00
Robin Bygrave 6828fa1786 #784 - DDL DB Migration - Add @ManyToOne does not generate Foreign key and index ddl statements in migration script 2016-07-25 20:44:15 +12:00
Robin Bygrave ba7e729ae1 #785 - Bump avaje-classpath-scanner-api dependency to 2.2 for Windows fixes to classpath-scanner 2016-07-25 11:39:41 +12:00
Rob BygraveandGitHub c3fba72a24 Merge pull request #781 from FOCONIS/master
FIX: PathTests - on Windows
2016-07-25 11:14:23 +12:00
Robin Bygrave ff401cfc72 [maven-release-plugin] prepare for next development iteration 2016-07-20 00:03:20 +12:00
Roland Praml cf9eb4ed97 FIX: PathTests - they fail on windows machine, because the OS translates "/tmp" to "c:\tmp". bumped classpath-canner to current API version 2016-07-19 13:25:53 +02:00
184 changed files with 2899 additions and 1680 deletions
+15 -16
View File
@@ -7,12 +7,12 @@
<version>1.1</version>
</parent>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>7.19.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean</artifactId>
<version>8.2.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
@@ -37,7 +37,7 @@
<scm>
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
<tag>avaje-ebeanorm-7.19.1</tag>
<tag>ebean-8.2.1</tag>
</scm>
<dependencies>
@@ -69,19 +69,19 @@
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner-api</artifactId>
<version>2.1</version>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner</artifactId>
<version>2.1.1</version>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-dbmigration</artifactId>
<version>1.1.1</version>
<version>1.2.1</version>
</dependency>
<dependency>
@@ -172,9 +172,9 @@
</dependency>
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-agent</artifactId>
<version>4.11.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>8.1.1</version>
<scope>test</scope>
</dependency>
@@ -247,16 +247,15 @@
</plugin>
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>4.11.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>8.1.1</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<classSource>target/test-classes</classSource>
<!--<packages>com.avaje.tests.**</packages>-->
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
@@ -304,7 +303,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<doctitle>Ebean 7</doctitle>
<doctitle>Ebean 8</doctitle>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
@@ -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();
}
+7
View File
@@ -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.
* <p>
+76 -8
View File
@@ -739,20 +739,46 @@ public interface EbeanServer {
<T> T getReference(Class<T> 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()
* @see Query#findCount()
* @see Query#findFutureCount()
*/
<T> int findCount(Query<T> query, Transaction transaction);
/**
* Deprecated in favor of findCount()
*
* Return the number of 'top level' or 'root' entities this query should return.
* @deprecated
*/
<T> int findRowCount(Query<T> query, Transaction transaction);
/**
* Return the Id values of the query as a List.
*
* @see com.avaje.ebean.Query#findIds()
* @see Query#findIds()
*/
<T> List<Object> findIds(Query<T> query, Transaction transaction);
<A> List<A> findIds(Query<?> query, Transaction transaction);
/**
* Return a QueryIterator for the query.
* <p>
* 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).
* </p>
* <p>
* 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.
* </p>
*
* @see Query#findIterate()
* @see Query#findEach(QueryEachConsumer)
* @see Query#findEachWhile(QueryEachWhileConsumer)
*/
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
* Execute the query visiting the each bean one at a time.
@@ -868,7 +894,15 @@ public interface EbeanServer {
* @return a Future object for the row count query
* @see com.avaje.ebean.Query#findFutureRowCount()
*/
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
/**
* Deprecated in favor of findFutureCount().
*
* Execute find row count query in a background thread.
* @deprecated
*/
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
/**
* Execute find Id's query in a background thread.
@@ -971,7 +1005,41 @@ public interface EbeanServer {
* @return the map of fetched beans.
* @see Query#findMap()
*/
<T> Map<?, T> findMap(Query<T> query, Transaction transaction);
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
/**
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*
* @see Query#findSingleAttributeList()
*/
<A> List<A> findSingleAttributeList(Query<?> query, Transaction transaction);
/**
* Execute the query returning at most one entity bean or null (if no matching
@@ -31,7 +31,7 @@ import java.util.Set;
* more methods than you would initially expect (the ones duplicated from
* Query).
* </p>
*
*
* @see Query#where()
*/
public interface ExpressionList<T> {
@@ -83,14 +83,14 @@ public interface ExpressionList<T> {
/**
* Add an orderBy clause to the query.
*
*
* @see Query#orderBy(String)
*/
Query<T> orderBy(String orderBy);
/**
* Add an orderBy clause to the query.
*
*
* @see Query#orderBy(String)
*/
Query<T> setOrderBy(String orderBy);
@@ -116,12 +116,6 @@ public interface ExpressionList<T> {
*/
Query<T> asDraft();
/**
* Deprecated in favour of setIncludeSoftDeletes().
*/
@Deprecated
Query<T> includeSoftDeletes();
/**
* Execute the query including soft deleted rows.
*/
@@ -147,6 +141,13 @@ public interface ExpressionList<T> {
*/
int update();
/**
* Execute the query iterating over the results.
*
* @see Query#findIterate()
*/
QueryIterator<T> findIterate();
/**
* Execute the query process the beans one at a time.
*
@@ -164,17 +165,17 @@ public interface ExpressionList<T> {
/**
* Execute the query returning a list.
*
*
* @see Query#findList()
*/
List<T> findList();
/**
* Execute the query returning the list of Id's.
*
*
* @see Query#findIds()
*/
List<Object> findIds();
<A> List<A> findIds();
/**
* Return the count of entities this query should return.
@@ -182,26 +183,60 @@ public interface ExpressionList<T> {
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
int findCount();
/**
* Deprecated in favor of findCount().
*
* @deprecated
*/
int findRowCount();
/**
* Execute the query returning a set.
*
*
* @see Query#findSet()
*/
Set<T> findSet();
/**
* Execute the query returning a map.
*
*
* @see Query#findMap()
*/
Map<?, T> findMap();
<K> Map<K, T> findMap();
/**
* Return a typed map specifying the key property and type.
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning a single bean or null (if no matching
@@ -225,9 +260,16 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureCount();
/**
* Deprecated in favor of findFutureCount().
*
* @deprecated
*/
FutureRowCount<T> findFutureRowCount();
/**
@@ -237,7 +279,7 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
@@ -249,7 +291,7 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the list result of the query
*/
FutureList<T> findFutureList();
@@ -312,7 +354,7 @@ public interface ExpressionList<T> {
/**
* Specify specific properties to fetch on the main/root bean (aka partial
* object).
*
*
* @see Query#select(String)
*/
Query<T> select(String properties);
@@ -337,28 +379,28 @@ public interface ExpressionList<T> {
/**
* Set the first row to fetch.
*
*
* @see Query#setFirstRow(int)
*/
Query<T> setFirstRow(int firstRow);
/**
* Set the maximum number of rows to fetch.
*
*
* @see Query#setMaxRows(int)
*/
Query<T> setMaxRows(int maxRows);
/**
* Set the name of the property which values become the key of a map.
*
*
* @see Query#setMapKey(String)
*/
Query<T> setMapKey(String mapKey);
/**
* Set to true to use the query for executing this query.
*
*
* @see Query#setUseCache(boolean)
*/
Query<T> setUseCache(boolean useCache);
@@ -619,7 +661,7 @@ public interface ExpressionList<T> {
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
* </p>
*
*
* <pre>{@code
*
* // create an example bean and set the properties
@@ -627,26 +669,26 @@ public interface ExpressionList<T> {
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
*
* List&lt;Customer&gt; 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();
*
*
* }</pre>
*
*
* Similarly you can create an ExampleExpression
*
*
* <pre>{@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<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
*
* }</pre>
@@ -748,7 +790,7 @@ public interface ExpressionList<T> {
* Exists expression
*/
ExpressionList<T> exists(Query<?> subQuery);
/**
* Not exists expression
*/
@@ -775,7 +817,7 @@ public interface ExpressionList<T> {
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
*
* @param propertyMap
* a map keyed by property names.
*/
@@ -29,8 +29,7 @@ import java.io.Serializable;
* // Find Orders join details using a single SQL query
* }</pre>
* <p>
* 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
* </p>
*
* <pre>{@code
@@ -117,7 +116,7 @@ import java.io.Serializable;
* <pre>{@code
* List<Order> list = Ebean.find(Order.class)
* .fetch("customer","name", new FetchConfig().lazy(5))
* .fetch("customer.contacts",&quotcontactName, phone, email&quot)
* .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
*
* }</pre>
*
@@ -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.
* </p>
*
* @author rbygrave
*/
public interface FutureIds<T> extends Future<List<Object>> {
@@ -19,16 +17,4 @@ public interface FutureIds<T> extends Future<List<Object>> {
*/
Query<T> getQuery();
/**
* Return the list of Id's which could be partially populated.
* <p>
* That is the query getting the id's could still be running and adding id's
* to this list.
* </p>
* <p>
* To get the list of Id's ensuring the query has finished use the
* {@link Future#get()} method instead of this one.
* </p>
*/
List<Object> getPartialIds();
}
+24 -17
View File
@@ -495,7 +495,7 @@ public abstract class Model {
/**
* Return typically a different EbeanServer to the default.
* <p>
* 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
@@ -598,7 +598,7 @@ public abstract class Model {
* <p>
* Equivalent to {@link Query#findIds()}
*/
public List<Object> findIds() {
public <A> List<A> findIds() {
return query().findIds();
}
@@ -660,36 +660,43 @@ public abstract class Model {
* <p>
* Equivalent to {@link Query#findMap()}
*/
public Map<?, T> findMap() {
public <K> Map<K, T> findMap() {
return query().findMap();
}
/**
* Executes the query and returns the results as a map of the objects specifying the map key
* property.
* <p>
* Equivalent to {@link Query#findMap(String, Class)}
*/
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
return query().findMap(keyProperty, keyType);
}
/**
* Executes a find row count query in a background thread.
* <p>
* Equivalent to {@link Query#findFutureRowCount()}
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureCount() {
return query().findFutureCount();
}
/**
* Deprecated in favor of findFutureCount().
* <p>
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureRowCount() {
return query().findFutureRowCount();
return query().findFutureCount();
}
/**
* Returns the total number of entities for this type. *
* <p>
* 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();
}
/**
@@ -110,6 +110,13 @@ public interface PagedList<T> {
* wrapped in the unchecked PersistenceException (which might be preferrable).
* </p>
*/
void loadCount();
/**
* Deprecated in favor of loadCount().
*
* @deprecated
*/
void loadRowCount();
/**
@@ -138,6 +145,13 @@ public interface PagedList<T> {
*
* }</pre>
*/
Future<Integer> getFutureCount();
/**
* Deprecated in favor of getFutureCount().
*
* @deprecated
*/
Future<Integer> getFutureRowCount();
/**
@@ -170,6 +184,13 @@ public interface PagedList<T> {
*
* }</pre>
*/
int getTotalCount();
/**
* Deprecated in favor of getTotalCount().
*
* @deprecated
*/
int getTotalRowCount();
/**
+311 -227
View File
@@ -13,10 +13,10 @@ import java.util.Set;
* <p>
* Example: Create the query using the API.
* </p>
*
* <p>
* <pre>{@code
*
* List<Order> orderList =
* List<Order> 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();
*
*
* ...
* }</pre>
*
* <p>
* Example: The same query using the query language
* </p>
*
* <pre>{@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<Order> query = ebeanServer.createQuery(Order.class, oql);
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
*
* List<Order> orderList = query.findList();
* ...
* }</pre>
*
* <p>
* Example: Using a named query called "with.cust.and.details"
* </p>
*
* <pre>{@code
*
* Query<Order> query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
*
* List<Order> orderList = query.findList();
* ...
* }</pre>
*
* <h3>AutoTune</h3>
* <p>
* 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.
* </p>
*
* <h3>Query Language</h3>
* <p>
* <b>Partial Objects</b>
@@ -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.
* </p>
*
* <pre>{@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} ] ]
* }</pre>
*
* <p>
* <b>FIND</b> <b>{bean type}</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* <b>SELECT</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* </p>
* <p>
* 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.
* </p>
* <p>
* In object graph terms the <em>find</em> clause specifies the type of bean at
* the root level and the <em>fetch</em> clauses specify the paths of the object
* graph to populate.
* </p>
* <p>
* <b>FETCH</b> <b>{associated property}</b> [ ( <i>*</i> | <i>{fetch
* properties}</i> ) ]
* <b>FETCH</b> <b>{path}</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
* </p>
* <p>
* 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.
* </p>
* <p>
* For fetch of a path we can optionally specify a list of properties to fetch.
@@ -161,52 +143,34 @@ import java.util.Set;
* </p>
* <h4>Examples of Ebean's Query Language</h4>
* <p>
* Find orders fetching all its properties
* </p>
*
* <pre>{@code
* find order
* }</pre>
*
* <p>
* Find orders fetching all its properties
* </p>
*
* <pre>{@code
* find order (*)
* }</pre>
*
* <p>
* 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.
* </p>
*
* <pre>{@code
* find order (shipDate, status)
*
* select (shipDate, status)
*
* }</pre>
*
* <p>
* Find orders with a named bind variable (that will need to be bound via
* {@link Query#setParameter(String, Object)}).
* </p>
*
* <pre>{@code
* find order
*
* where customer.name like :custLike
*
* }</pre>
*
* <p>
* Find orders and also fetch the customer with a named bind parameter. This
* will fetch and populate both the order and customer objects.
* </p>
*
* <pre>{@code
* find order
*
* fetch customer
* where customer.id = :custId
*
* }</pre>
*
* <p>
* 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.
* </p>
*
* <pre>{@code
* find order
*
* fetch customer (name)
* fetch customer.shippingAddress
* fetch details
* fetch details.product (sku, name)
*
* }</pre>
*
* <h3>Early parsing of the Query</h3>
* <p>
* 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).
* </p>
* <p>
* The thought is that you can use named queries as a 'starting point' and then
* modify the query to suit specific needs.
* </p>
* <h3>Building the Where clause</h3>
* <p>
* 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.
* <ul>
* <li>where(String addToWhereClause)</li>
* <li>where().add(Expression expression)</li>
* <li>where().eq(propertyName, value).like(propertyName , value)...</li>
* </ul>
* </p>
* <p>
* The full WHERE clause is constructed by appending together
* <li>original query where clause (Named query or query.setQuery(String oql))</li>
* <li>clauses added via query.where(String addToWhereClause)</li>
* <li>clauses added by Expression objects</li>
* </p>
* <p>
* The above is the order that these are clauses are appended to give the full
* WHERE clause.
* </p>
* <h3>Design Goal</h3>
* <p>
* 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.
* </p>
* <p>
* 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} .
* </p>
*
* @param <T>
* the type of Entity bean this query will fetch.
*
* @param <T> the type of Entity bean this query will fetch.
*/
public interface Query<T> {
@@ -289,7 +206,7 @@ public interface Query<T> {
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
* <p>
* To perform this query the DB must have underlying history tables.
* To perform this query the DB must have underlying history tables.
* </p>
*
* @param asOf the date time in the past at which you want to view the data
@@ -325,7 +242,7 @@ public interface Query<T> {
* Specify the PersistenceContextScope to use for this query.
* <p/>
* 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}.
* <p/>
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
* <p/>
@@ -392,14 +309,15 @@ public interface Query<T> {
Query<T> 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.
* <p>
* 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.
* </p>
* <p>
* Use {@link #fetch(String, String)} to specify specific properties to fetch
* on other non-root level paths of the object graph.
* </p>
*
* <pre>{@code
*
* List<Customer> customers =
@@ -412,42 +330,33 @@ public interface Query<T> {
*
* }</pre>
*
* @param fetchProperties
* the properties to fetch for this bean (* = all properties).
* @param fetchProperties the properties to fetch for this bean (* = all properties).
*/
Query<T> select(String fetchProperties);
/**
* Specify a path to <em>fetch</em> with its specific properties to include
* (aka partial object).
* Specify a path to fetch eagerly including specific properties.
* <p>
* 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().
* </p>
*
* <pre>{@code
*
* // query orders...
* List<Order> 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();
* }</pre>
*
* <p>
* 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.
* </p>
*
* <pre>{@code
*
* // fetch customers (their id, name and status)
@@ -458,19 +367,66 @@ public interface Query<T> {
* .findList();
*
* }</pre>
*
* @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<T> fetch(String path, String fetchProperties);
/**
* Fetch the path and properties using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, new FetchConfig().query())
*
* }</pre>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @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<T> fetchQuery(String path, String fetchProperties);
/**
* Fetch the path and properties lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, new FetchConfig().lazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @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<T> fetchLazy(String path, String fetchProperties);
/**
* Additionally specify a FetchConfig to use a separate query or lazy loading
* to load this path.
*
* <pre>{@code
*
* // fetch customers (their id, name and status)
@@ -481,13 +437,17 @@ public interface Query<T> {
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig);
Query<T> 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.
* <p>
* 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().
* </p>
* <pre>{@code
*
@@ -500,16 +460,59 @@ public interface Query<T> {
*
* }</pre>
*
* @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<T> fetch(String path);
/**
* Fetch the path eagerly using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, new FetchConfig().query())
*
* }</pre>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @param path the property path we wish to fetch eagerly
*/
Query<T> fetchQuery(String path);
/**
* Fetch the path lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, new FetchConfig().lazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
*/
Query<T> fetchLazy(String path);
/**
* Additionally specify a JoinConfig to specify a "query join" and or define
* the lazy loading query.
*
*
* <pre>{@code
*
* // fetch customers (their id, name and status)
@@ -536,10 +539,50 @@ public interface Query<T> {
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
*
*
* @see EbeanServer#findIds(Query, Transaction)
*/
List<Object> findIds();
<A> List<A> findIds();
/**
* Execute the query iterating over the results.
* <p>
* 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.
* </p>
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* </p>
* <p>
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
* the jdbc statement and resultSet are closed at the end of the iteration.
* </p>
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <pre>{@code
*
* Query<Customer> query =
* ebeanServer.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id");
*
* QueryIterator<Customer> it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* } finally {
* // close the underlying resources
* it.close();
* }
*
* }</pre>
*/
QueryIterator<T> findIterate();
/**
* Execute the query processing the beans one at a time.
@@ -549,6 +592,11 @@ public interface Query<T> {
* (unlike #findList #findSet etc)
* </p>
* <p>
* 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.
* </p>
* <p>
* 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<T> {
* iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
* with Java8 closures.
* </p>
*
* <pre>{@code
*
* ebeanServer.find(Customer.class)
@@ -578,8 +625,7 @@ public interface Query<T> {
*
* }</pre>
*
* @param consumer
* the consumer used to process the queried beans.
* @param consumer the consumer used to process the queried beans.
*/
void findEach(QueryEachConsumer<T> consumer);
@@ -587,12 +633,15 @@ public interface Query<T> {
* Execute the query using callbacks to a visitor to process the resulting
* beans one at a time.
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* <pre>{@code
*
* ebeanServer.find(Customer.class)
@@ -611,8 +660,7 @@ public interface Query<T> {
*
* }</pre>
*
* @param consumer
* the consumer used to process the queried beans.
* @param consumer the consumer used to process the queried beans.
*/
void findEachWhile(QueryEachWhileConsumer<T> consumer);
@@ -621,7 +669,6 @@ public interface Query<T> {
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
*
* <pre>{@code
*
* List<Customer> customers =
@@ -640,7 +687,6 @@ public interface Query<T> {
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
*
* <pre>{@code
*
* Set<Customer> customers =
@@ -663,24 +709,50 @@ public interface Query<T> {
* 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.
* </p>
*
* <pre>{@code
*
* Map<?, Product> map =
* Map<String, Product> map =
* ebeanServer.find(Product.class)
* .setMapKey("sku")
* .findMap();
*
* }</pre>
*
*
* @see EbeanServer#findMap(Query, Transaction)
*/
Map<?, T> findMap();
<K> Map<K, T> findMap();
/**
* Return a typed map specifying the key property and type.
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning either a single bean or null (if no matching
@@ -693,7 +765,6 @@ public interface Query<T> {
* This is useful when your predicates dictate that your query should only
* return 0 or 1 results.
* </p>
*
* <pre>{@code
*
* // assuming the sku of products is unique...
@@ -703,16 +774,14 @@ public interface Query<T> {
* .findUnique();
* ...
* }</pre>
*
* <p>
* It is also useful with finding objects by their id when you want to specify
* further join information.
* </p>
*
* <pre>{@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<T> {
/**
* Return versions of a @History entity bean.
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*/
List<Version<T>> findVersions();
@@ -745,8 +814,8 @@ public interface Query<T> {
/**
* Return versions of a @History entity bean between the 2 timestamps.
* <p>
* 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.
* </p>
*/
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
@@ -774,6 +843,15 @@ public interface Query<T> {
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
int findCount();
/**
* Deprecated in favor of findCount().
* <p>
* Return the count of entities this query should return.
*
* @deprecated
*/
int findRowCount();
/**
@@ -783,9 +861,24 @@ public interface Query<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureCount();
/**
* Deprecated in favor of findFutureCount().
* <p>
* Execute find row count query in a background thread.
* <p>
* 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).
* </p>
*
* @return a Future object for the row count query
* @deprecated
*/
FutureRowCount<T> findFutureRowCount();
/**
@@ -795,7 +888,7 @@ public interface Query<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
@@ -821,7 +914,6 @@ public interface Query<T> {
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
*
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
@@ -843,24 +935,21 @@ public interface Query<T> {
/**
* Set a named bind parameter. Named parameters have a colon to prefix the name.
*
* <pre>{@code
*
* // a query with a named parameter
* String oql = "find order where status = :orderStatus";
*
*
* Query<Order> query = ebeanServer.find(Order.class, oql);
*
*
* // bind the named parameter
* query.bind("orderStatus", OrderStatus.NEW);
* List<Order> list = query.findList();
*
* }</pre>
*
* @param name
* the parameter name
* @param value
* the parameter value
*
* @param name the parameter name
* @param value the parameter value
*/
Query<T> setParameter(String name, Object value);
@@ -868,25 +957,22 @@ public interface Query<T> {
* 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.
*
* <pre>{@code
*
* // a query with a positioned parameter
* String oql = "where status = ? order by id desc";
*
*
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
*
*
* // bind the parameter
* query.setParameter(1, OrderStatus.NEW);
*
*
* List<Order> list = query.findList();
*
* }</pre>
*
* @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<T> setParameter(int position, Object value);
@@ -896,7 +982,6 @@ public interface Query<T> {
* You can use this to have further control over the query. For example adding
* fetch joins.
* </p>
*
* <pre>{@code
*
* Order order =
@@ -919,10 +1004,9 @@ public interface Query<T> {
/**
* Add a single Expression to the where clause returning the query.
*
* <pre>{@code
*
* List<Order> newOrders =
* List<Order> newOrders =
* ebeanServer.find(Order.class)
* .where().eq("status", Order.NEW)
* .findList();
@@ -936,7 +1020,6 @@ public interface Query<T> {
* 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.
*
* <pre>{@code
*
* List<Order> orders =
@@ -947,9 +1030,9 @@ public interface Query<T> {
* .findList();
*
* }</pre>
*
* @see Expr
*
* @return The ExpressionList for adding expressions to.
* @see Expr
*/
ExpressionList<T> where();
@@ -984,9 +1067,8 @@ public interface Query<T> {
* 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.
* </p>
*
* <pre>{@code
*
*
* List<Customer> list =
* ebeanServer.find(Customer.class)
* // .fetch("orders", new FetchConfig().lazy())
@@ -995,20 +1077,17 @@ public interface Query<T> {
* .where().ilike("name", "rob%")
* .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
* .findList();
*
*
* }</pre>
*
* <p>
* 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.
* </p>
*
* @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<T> filterMany(String propertyName);
@@ -1021,9 +1100,9 @@ public interface Query<T> {
* Note that this returns the ExpressionList (so you can add multiple
* expressions to the query in a fluent API way).
* </p>
*
* @see Expr
*
* @return The ExpressionList for adding more expressions to.
* @see Expr
*/
ExpressionList<T> having();
@@ -1037,9 +1116,8 @@ public interface Query<T> {
* than the ExpressionList. This is useful when you want to further specify
* something on the query.
* </p>
*
* @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<T> having(Expression addExpressionToHaving);
@@ -1151,9 +1229,8 @@ public interface Query<T> {
/**
* 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<T> setMaxRows(int maxRows);
@@ -1162,11 +1239,10 @@ public interface Query<T> {
* <p>
* If no property is set then the id property is used.
* </p>
*
* <pre>{@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<T> {
* .findMap();
*
* }</pre>
*
* @param mapKey
* the property to use as keys for a map.
*
* @param mapKey the property to use as keys for a map.
*/
Query<T> setMapKey(String mapKey);
@@ -1203,7 +1278,7 @@ public interface Query<T> {
/**
* Set to true if this query should execute against the doc store.
* <p>
* When setting this you may also consider disabling lazy loading.
* When setting this you may also consider disabling lazy loading.
* </p>
*/
Query<T> setUseDocStore(boolean useDocStore);
@@ -1226,9 +1301,8 @@ public interface Query<T> {
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @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<T> setTimeout(int secs);
@@ -1238,6 +1312,16 @@ public interface Query<T> {
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*/
Query<T> setBufferFetchSizeHint(int fetchSize);
@@ -1260,7 +1344,7 @@ public interface Query<T> {
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
/**
* Set root table alias.
*/
@@ -1274,7 +1358,7 @@ public interface Query<T> {
/**
* Set true if you want to disable lazy loading.
* <p>
* 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.
* </p>
*/
Query<T> setDisableLazyLoading(boolean disableLazyLoading);
@@ -0,0 +1,67 @@
package com.avaje.ebean;
import java.util.Iterator;
/**
* Used to provide iteration over query results.
* <p>
* 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).
* </p>
* <p>
* 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.
* </p>
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* </p>
*
* <pre>{@code
*
* Query<Customer> query = server.find(Customer.class)
* .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 underlying resources
* it.close();
* }
*
* }</pre>
*
* @param <T>
* the type of entity bean in the iteration
*/
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
/**
* Returns <tt>true</tt> 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();
}
@@ -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.
+1 -2
View File
@@ -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);
+51 -3
View File
@@ -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.
* <p>
* This is similar to commit() but leaves the transaction "Active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* </ul>
*/
void commitAndContinue() throws RollbackException;
/**
* Commit the transaction.
* <p>
* This performs commit and completes the transaction closing underlying resources and
* marking the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void commit() throws RollbackException;
/**
* Rollback the transaction.
* <p>
* This performs rollback, closes underlying resources and marks the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Call rollback on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
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);
@@ -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.
* <p>
@@ -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));
}
@@ -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();
}
@@ -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<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
private List<TransactionEventListener> transactionEventListeners = new ArrayList<TransactionEventListener>();
/**
* By default inserts are included in the change log.
@@ -2052,35 +2050,6 @@ public class ServerConfig {
this.persistControllers = persistControllers;
}
/**
* Register a TransactionEventListener instance
* <p>
* Note alternatively you can use {@link #setTransactionEventListeners(List)}
* to set all the TransactionEventListener instances.
* </p>
*/
public void add(TransactionEventListener listener) {
transactionEventListeners.add(listener);
}
/**
* Return the TransactionEventListener instances.
*/
public List<TransactionEventListener> getTransactionEventListeners() {
return transactionEventListeners;
}
/**
* Register all the TransactionEventListener instances.
* <p>
* Note alternatively you can use {@link #add(TransactionEventListener)} to
* add TransactionEventListener instances one at a time.
* </p>
*/
public void setTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
this.transactionEventListeners = transactionEventListeners;
}
/**
* Register a BeanPersistListener instance.
* <p>
@@ -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
*/
@@ -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();
@@ -96,7 +96,13 @@ public class DdlGenerator {
Transaction transaction = server.createTransaction();
Connection connection = transaction.getConnection();
try {
if (expectErrors) {
connection.setAutoCommit(true);
}
int count = runner.runAll(content, connection);
if (expectErrors) {
connection.setAutoCommit(false);
}
transaction.commit();
return count;
@@ -583,6 +583,12 @@ public class BaseTableDdl implements TableDdl {
}
}
for (Column column : columns) {
if (hasValue(column.getReferences())) {
writeForeignKey(writer, tableName, column);
}
}
// add a bit of whitespace
writer.apply().end();
}
@@ -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);
@@ -1,7 +1,5 @@
package com.avaje.ebean.event;
import java.util.Set;
import com.avaje.ebean.config.ServerConfig;
/**
@@ -1,7 +1,5 @@
package com.avaje.ebean.event;
import java.util.Set;
/**
* Used to enhance or override the default bean persistence mechanism.
* <p>
@@ -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);
}
@@ -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
}
}
@@ -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;
}
/**
@@ -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;
}
/**
@@ -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.
@@ -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 {
@@ -145,7 +145,7 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* the query has finished (if executing in a background thread).
* </p>
*/
<T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
<A> List<A> findIdsWithCopy(Query<?> query, Transaction t);
/**
* Execute the findRowCount query but without copying the query.
@@ -78,6 +78,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
ID_LIST,
/**
* Find single attribute.
*/
ATTRIBUTE,
/**
* Find rowCount.
*/
@@ -222,6 +227,16 @@ public interface SpiQuery<T> extends Query<T> {
*/
Timestamp getAsOf();
/**
* Return true if the base table is using history.
*/
boolean isAsOfBaseTable();
/**
* Set when the base table is using history.
*/
void setAsOfBaseTable();
/**
* Increment the counter of tables used in 'As Of' query.
*/
@@ -236,21 +251,6 @@ public interface SpiQuery<T> extends Query<T> {
List<String> getSoftDeletePredicates();
/**
* Set the list of Id's that is being populated.
* <p>
* 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.
* </p>
*/
void setIdList(List<Object> ids);
/**
* Return the list of Id's that is currently being fetched by a background
* thread.
*/
List<Object> getIdList();
/**
* Return a copy of the query.
*/
@@ -331,6 +331,24 @@ public interface SpiQuery<T> extends Query<T> {
*/
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.
* <p>
* distinct and single attribute queries exclude the Id property.
* </p>
*/
boolean isWithId();
/**
* Set a filter to a join path.
*/
@@ -583,9 +601,15 @@ public interface SpiQuery<T> extends Query<T> {
*/
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.
@@ -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.
*/
@@ -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;
@@ -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;
@@ -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);
}
}
@@ -84,4 +84,9 @@ public class DefaultBeanState implements BeanState {
public boolean isDisableLazyLoad() {
return intercept.isDisableLazyLoad();
}
@Override
public void resetForInsert() {
intercept.setNew();
}
}
@@ -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());
@@ -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 <T> Map<?, T> findMap(Query<T> query, Transaction t) {
public <K, T> Map<K, T> findMap(Query<T> query, Transaction t) {
SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
return (Map<?, T>) result;
return (Map<K, T>) result;
}
try {
request.initTransIfRequired();
return (Map<?, T>) request.findMap();
return (Map<K, T>) request.findMap();
} finally {
request.endTransIfRequired();
}
}
public <T> int findRowCount(Query<T> query, Transaction t) {
@Override
@SuppressWarnings("unchecked")
public <A> List<A> findSingleAttributeList(Query<?> query, Transaction t) {
SpiOrmQueryRequest request = createQueryRequest(Type.ATTRIBUTE, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
return (List<A>) result;
}
try {
request.initTransIfRequired();
return (List<A>) request.findSingleAttributeList();
} finally {
request.endTransIfRequired();
}
}
public <T> int findCount(Query<T> query, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
return findRowCountWithCopy(copy, t);
}
public <T> int findRowCount(Query<T> query, Transaction t) {
return findCount(query, t);
}
public <T> int findRowCountWithCopy(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ROWCOUNT, query, t);
@@ -1170,16 +1190,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
public <T> List<Object> findIds(Query<T> query, Transaction t) {
public <A> List<A> findIds(Query<?> query, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
return findIdsWithCopy(copy, t);
return findIdsWithCopy(((SpiQuery<?>) query).copy(), t);
}
public <T> List<Object> findIdsWithCopy(Query<T> query, Transaction t) {
public <A> List<A> findIdsWithCopy(Query<?> query, Transaction t) {
SpiOrmQueryRequest<T> 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 <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
public <T> FutureRowCount<T> findFutureCount(Query<T> q, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) q).copy();
copy.setFutureFetch(true);
@@ -1228,17 +1246,15 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return queryFuture;
}
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
return findFutureCount(q, t);
}
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) 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<Object> idList = Collections.synchronizedList(new ArrayList<Object>());
copy.setIdList(idList);
Transaction newTxn = createTransaction();
CallableQueryIds<T> call = new CallableQueryIds<T>(this, copy, newTxn);
@@ -1286,6 +1302,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return new LimitOffsetPagedList<T>(this, spiQuery);
}
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
try {
request.initTransIfRequired();
return request.findIterate();
} catch (RuntimeException ex) {
request.endTransIfRequired();
throw ex;
}
}
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
@@ -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);
}
/**
@@ -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 {
*/
<T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
/**
* Execute the findSingleAttributeList query.
*/
<A> List<A> findSingleAttributeList(OrmQueryRequest<?> request);
/**
* Execute the findVersions query.
*/
<T> List<Version<T>> findVersions(OrmQueryRequest<T> request);
/**
@@ -36,7 +44,7 @@ public interface OrmQueryEngine {
/**
* Execute the find id's query.
*/
<T> BeanIdList findIds(OrmQueryRequest<T> request);
<A> List<A> findIds(OrmQueryRequest<?> request);
/**
* Execute the query as a delete statement.
@@ -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<T> extends BeanRequest implements BeanQueryRe
return queryEngine.findRowCount(this);
}
public List<Object> findIds() {
BeanIdList idList = queryEngine.findIds(this);
return idList.getIdList();
public <A> List<A> findIds() {
return queryEngine.findIds(this);
}
public void findEach(QueryEachConsumer<T> consumer) {
@@ -373,6 +372,14 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
return (Map<?, ?>) queryEngine.findMany(this);
}
/**
* Execute the findSingleAttributeList query.
*/
@Override
public <A> List<A> findSingleAttributeList() {
return queryEngine.findSingleAttributeList(this);
}
/**
* Return a bean specific finder if one has been set.
*/
@@ -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<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate {
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate, PreGetterCallback {
private final BeanManager<T> beanManager;
@@ -137,6 +138,11 @@ public final class PersistRequestBean<T> 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<T> mgr, SpiTransaction t,
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse, boolean publish) {
@@ -239,8 +245,17 @@ public final class PersistRequestBean<T> 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<T> 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<T> 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() {
@@ -1,60 +0,0 @@
package com.avaje.ebeaninternal.server.core;
import java.util.Iterator;
/**
* Used to provide iteration over query results.
* <p>
* 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).
* </p>
*
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* QueryIterator&lt;Customer&gt; it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer...
* }
* } finally {
* // close the associated resources
* it.close();
* }
* </pre>
*
* @author rbygrave
*
* @param <T>
* the type of entity bean in the iteration
*/
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
/**
* Returns <tt>true</tt> 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();
}
@@ -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<T> extends DocQueryRequest<T> {
/**
* Execute the find ids query.
*/
List<Object> findIds();
<A> List<A> findIds();
/**
* Execute the find returning a QueryIterator and visitor pattern.
@@ -107,6 +108,11 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
*/
Map<?, ?> findMap();
/**
* Execute the findSingleAttributeList query.
*/
<A> List<A> findSingleAttributeList();
/**
* Try to get the query result from the query cache.
*/
@@ -41,7 +41,7 @@ final class TransWrapper {
void rollbackIfCreated() {
if (wasCreated){
transaction.rollback();
transaction.rollbackIfActive();
}
}
@@ -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<Class<?>> beanPostLoadList = new ArrayList<Class<?>>();
private final List<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
private final List<Class<?>> beanFindControllerList = new ArrayList<Class<?>>();
private final List<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
@@ -70,7 +67,6 @@ public class BootupClasses implements ClassFilter {
private final List<BeanPostLoad> beanPostLoadInstances = new ArrayList<BeanPostLoad>();
private final List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
private final List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
private final List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
private Class<?> changeLogPrepareClass;
private Class<?> changeLogListenerClass;
@@ -181,19 +177,6 @@ public class BootupClasses implements ClassFilter {
}
}
/**
* Add TransactionEventListeners instances.
*/
public void addTransactionEventListeners(List<TransactionEventListener> 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<BeanPersistListener> listenerInstances) {
if (listenerInstances != null) {
for (BeanPersistListener l : listenerInstances) {
@@ -351,14 +334,6 @@ public class BootupClasses implements ClassFilter {
return idGeneratorInstances;
}
public List<TransactionEventListener> 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;
@@ -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;
@@ -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;
@@ -1173,6 +1173,13 @@ public class BeanProperty implements ElPropertyValue, Property {
return excludedFromHistory;
}
/**
* Return true if this is a ManyToMany with history support (on the intersection table).
*/
public boolean isManyToManyWithHistory() {
return !excludedFromHistory && descriptor.isHistorySupport();
}
/**
* Return true if this property only exists on the draft table.
*/
@@ -357,7 +357,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
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);
@@ -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;
@@ -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;
}
}
@@ -572,7 +572,7 @@ public class DeployBeanDescriptor<T> {
* Return the base table with as of suffix.
*/
public String getBaseTableAsOf() {
return baseTableAsOf;
return historySupport ? baseTableAsOf : baseTable;
}
/**
@@ -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();
@@ -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.
@@ -253,11 +253,6 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.asDraft();
}
@Override
public Query<T> includeSoftDeletes() {
return setIncludeSoftDeletes();
}
@Override
public Query<T> setIncludeSoftDeletes() {
return query.setIncludeSoftDeletes();
@@ -323,9 +318,14 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.findFutureIds();
}
@Override
public FutureRowCount<T> findFutureCount() {
return query.findFutureCount();
}
@Override
public FutureRowCount<T> findFutureRowCount() {
return query.findFutureRowCount();
return findFutureCount();
}
@Override
@@ -339,15 +339,25 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public int findRowCount() {
return query.findRowCount();
public int findCount() {
return query.findCount();
}
@Override
public List<Object> findIds() {
public int findRowCount() {
return findCount();
}
@Override
public <A> List<A> findIds() {
return query.findIds();
}
@Override
public QueryIterator<T> findIterate() {
return query.findIterate();
}
@Override
public void findEach(QueryEachConsumer<T> consumer) {
query.findEach(consumer);
@@ -369,13 +379,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public Map<?, T> findMap() {
public <K> Map<K, T> findMap() {
return query.findMap();
}
@Override
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
return query.findMap(keyProperty, keyType);
public <A> List<A> findSingleAttributeList() {
return query.findSingleAttributeList();
}
@Override
@@ -48,9 +48,14 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
return rootQuery.findFutureList();
}
@Override
public FutureRowCount<T> findFutureCount() {
return rootQuery.findFutureCount();
}
@Override
public FutureRowCount<T> findFutureRowCount() {
return rootQuery.findFutureRowCount();
return findFutureCount();
}
@Override
@@ -59,13 +64,18 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
}
@Override
public Map<?, T> findMap() {
public <K> Map<K, T> findMap() {
return rootQuery.findMap();
}
@Override
public int findCount() {
return rootQuery.findCount();
}
@Override
public int findRowCount() {
return rootQuery.findRowCount();
return findCount();
}
@Override
@@ -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;
@@ -62,6 +63,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
* This is expected to only used after expressions are built via query language parsing.
* </p>
*/
@SuppressWarnings("unchecked")
public void simplify() {
exprList.simplifyEntries();
@@ -325,11 +327,6 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
return exprList.asDraft();
}
@Override
public Query<T> includeSoftDeletes() {
return setIncludeSoftDeletes();
}
@Override
public Query<T> setIncludeSoftDeletes() {
return exprList.setIncludeSoftDeletes();
@@ -361,15 +358,25 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
}
@Override
public FutureRowCount<T> findFutureRowCount() {
return exprList.findFutureRowCount();
public FutureRowCount<T> findFutureCount() {
return exprList.findFutureCount();
}
@Override
public List<Object> findIds() {
public FutureRowCount<T> findFutureRowCount() {
return findFutureCount();
}
@Override
public <A> List<A> findIds() {
return exprList.findIds();
}
@Override
public QueryIterator<T> findIterate() {
return exprList.findIterate();
}
@Override
public void findEach(QueryEachConsumer<T> consumer) {
exprList.findEach(consumer);
@@ -386,13 +393,13 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
}
@Override
public Map<?, T> findMap() {
public <K> Map<K, T> findMap() {
return exprList.findMap();
}
@Override
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
return exprList.findMap(keyProperty, keyType);
public <A> List<A> findSingleAttributeList() {
return exprList.findSingleAttributeList();
}
@Override
@@ -401,10 +408,15 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
}
@Override
public int findRowCount() {
public int findCount() {
return exprList.findRowCount();
}
@Override
public int findRowCount() {
return findCount();
}
@Override
public Set<T> findSet() {
return exprList.findSet();
@@ -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 {
@@ -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 {
@@ -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
@@ -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 {
@@ -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<DLoadBeanContext.LoadBuffer>();
this.currentBuffer = createBuffer(firstBatchSize);
@@ -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?");
}
@@ -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) {
@@ -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;
}
}
@@ -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;
@@ -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;
@@ -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.
*/
@@ -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;
@@ -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 <T> String buildUpdateSql(OrmQueryRequest<T> 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,26 +161,20 @@ 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);
}
/**
* Build the row count query.
*/
public <T> CQueryFetchIds buildFetchIdsQuery(OrmQueryRequest<T> request) {
public CQueryFetchSingleAttribute buildFetchAttributeQuery(OrmQueryRequest<?> request) {
SpiQuery<T> query = request.getQuery();
query.setSelectId();
SpiQuery<?> query = request.getQuery();
query.setSingleAttribute();
CQueryPredicates predicates = new CQueryPredicates(binder, request);
CQueryPlan queryPlan = request.getQueryPlan();
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 CQueryFetchSingleAttribute(request, predicates, queryPlan);
}
// use RawSql or generated Sql
@@ -188,13 +182,19 @@ public class CQueryBuilder {
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());
queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
return new CQueryFetchIds(request, predicates, sql);
return new CQueryFetchSingleAttribute(request, predicates, queryPlan);
}
/**
* Build the find ids query.
*/
public <T> CQueryFetchSingleAttribute buildFetchIdsQuery(OrmQueryRequest<T> request) {
request.getQuery().setSelectId();
return buildFetchAttributeQuery(request);
}
/**
@@ -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()) {
@@ -452,8 +450,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));
}
}
@@ -472,8 +470,7 @@ public class CQueryBuilder {
hasWhere = true;
}
int asOfCount = query.getAsOfTableCount();
if (asOfCount > 0 && !historySupport.isStandardsBased()) {
if (query.isAsOfBaseTable() && !historySupport.isStandardsBased()) {
hasWhere = appendWhere(hasWhere, sb);
sb.append(historySupport.getAsOfPredicate(request.getBaseTableAlias()));
}
@@ -489,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;
@@ -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.ebean.QueryIterator;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.lib.util.Str;
import com.avaje.ebeaninternal.server.persist.Binder;
@@ -89,29 +88,24 @@ public class CQueryEngine {
}
/**
* Build and execute the find Id's query.
* Build and execute the findSingleAttributeList query.
*/
public <T> BeanIdList findIds(OrmQueryRequest<T> request) {
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request);
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request);
return findAttributeList(request, rcQuery);
}
@SuppressWarnings("unchecked")
private <A> List<A> findAttributeList(OrmQueryRequest<?> request, CQueryFetchSingleAttribute rcQuery) {
try {
BeanIdList list = rcQuery.findIds();
List<A> list = (List<A>)rcQuery.findList();
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) {
@@ -119,6 +113,15 @@ public class CQueryEngine {
}
}
/**
* Build and execute the find Id's query.
*/
public <A> List<A> findIds(OrmQueryRequest<?> request) {
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchIdsQuery(request);
return findAttributeList(request, rcQuery);
}
private <T> void logGeneratedSql(OrmQueryRequest<T> request, String sql, String bindLog) {
String logSql = sql;
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
@@ -300,9 +303,10 @@ public class CQueryEngine {
SpiQuery<T> 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);
}
@@ -1,278 +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.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;
/**
* 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;
}
/**
* 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();
}
/**
* 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.
*/
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<Object> idList = query.getIdList();
if (idList == null) {
// running in foreground thread (not FutureIds query)
idList = Collections.synchronizedList(new ArrayList<Object>());
query.setIdList(idList);
}
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);
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();
}
}
/**
* Close the resources.
* <p>
* The jdbc resultSet and statement need to be closed. Its important that
* this method is called.
* </p>
*/
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<String, String> pathMap) {
// no-op
}
public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) {
// no-op
}
@Override
public boolean isDraftQuery() {
return false;
}
}
}
@@ -0,0 +1,172 @@
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.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.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Base compiled query request for single attribute queries.
*/
class CQueryFetchSingleAttribute {
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<Object> scalarType;
/**
* Create the Sql select based on the request.
*/
public CQueryFetchSingleAttribute(OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan plan) {
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.
*/
protected 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.
*/
protected List<Object> findList() throws SQLException {
long startNano = System.nanoTime();
try {
prepareExecute();
List<Object> result = new ArrayList<Object>();
while (dataReader.next()) {
result.add(scalarType.read(dataReader));
dataReader.resetColumnPosition();
rowCount++;
}
long exeNano = System.nanoTime() - startNano;
executionTimeMicros = (int) exeNano / 1000;
return result;
} finally {
close();
}
}
/**
* 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.
* <p>
* The jdbc resultSet and statement need to be closed. Its important that
* this method is called.
* </p>
*/
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);
}
}
}
@@ -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;
/**
@@ -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;
/**
@@ -266,4 +266,7 @@ public class CQueryPlan {
return stats.getLastQueryTime();
}
public BeanProperty getSingleProperty() {
return sqlTree.getRootNode().getSingleProperty();
}
}
@@ -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;
@@ -65,12 +64,18 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
return queryEngine.findRowCount(request);
}
public <T> BeanIdList findIds(OrmQueryRequest<T> request) {
public <A> List<A> findIds(OrmQueryRequest<?> request) {
flushJdbcBatchOnQuery(request);
return queryEngine.findIds(request);
}
@Override
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
flushJdbcBatchOnQuery(request);
return queryEngine.findSingleAttributeList(request);
}
public <T> QueryIterator<T> findIterate(OrmQueryRequest<T> request) {
// LIMITATION: You can not use QueryIterator to load bean cache
@@ -43,19 +43,27 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
this.firstRow = query.getFirstRow();
}
public void loadRowCount() {
getFutureRowCount();
public void loadCount() {
getFutureCount();
}
public Future<Integer> getFutureRowCount() {
public void loadRowCount() {
loadCount();
}
public Future<Integer> getFutureCount() {
synchronized (monitor) {
if (futureRowCount == null) {
futureRowCount = server.findFutureRowCount(query, null);
futureRowCount = server.findFutureCount(query, null);
}
return futureRowCount;
}
}
public Future<Integer> getFutureRowCount() {
return getFutureCount();
}
public List<T> getList() {
synchronized (monitor) {
if (list == null) {
@@ -67,7 +75,7 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
public int getTotalPageCount() {
int rowCount = getTotalRowCount();
int rowCount = getTotalCount();
if (rowCount == 0) {
return 0;
} else {
@@ -75,7 +83,7 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
}
}
public int getTotalRowCount() {
public int getTotalCount() {
synchronized (monitor) {
if (futureRowCount != null) {
try {
@@ -89,13 +97,17 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
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<T> implements PagedList<T> {
int first = firstRow + 1;
int last = firstRow + getList().size();
int total = getTotalRowCount();
int total = getTotalCount();
return first + to + last + of + total;
}
@@ -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<T> extends BaseFuture<List<Object>> implements Futur
return call.query;
}
public List<Object> getPartialIds() {
return call.query.getIdList();
}
public boolean cancel(boolean mayInterruptIfRunning) {
call.query.cancel();
return super.cancel(mayInterruptIfRunning);
@@ -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).
*/
@@ -153,4 +138,10 @@ public class SqlTree {
return encryptedProps;
}
/**
* Return true if the query has a many join.
*/
public boolean hasMany() {
return manyProperty != null || rootNode.hasMany();
}
}
@@ -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();
@@ -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<?>) {
@@ -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;
@@ -57,4 +58,15 @@ public interface SqlTreeNode {
* Load a version of a @History bean with effective dates.
*/
<T> Version<T> loadVersion(DbReadContext ctx) throws SQLException;
/**
* Return true if the query has a many join.
*/
boolean hasMany();
/**
* Return the property for singleAttribute query.
*/
BeanProperty getSingleProperty();
}
@@ -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.
*/
@@ -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.
*/
@@ -137,6 +130,11 @@ public class SqlTreeNodeBean implements SqlTreeNode {
pathMap = createPathMap(prefix, desc);
}
@Override
public BeanProperty getSingleProperty() {
return properties[0];
}
private Map<String, String> createPathMap(String prefix, BeanDescriptor<?> desc) {
BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
@@ -507,6 +505,9 @@ public class SqlTreeNodeBean implements SqlTreeNode {
if (desc.isHistorySupport()) {
query.incrementAsOfTableCount();
}
if (lazyLoadParent != null && lazyLoadParent.isManyToManyWithHistory()) {
query.incrementAsOfTableCount();
}
if (intersectionAsOfTableAlias) {
query.incrementAsOfTableCount();
}
@@ -567,4 +568,14 @@ public class SqlTreeNodeBean implements SqlTreeNode {
return true;
}
@Override
public boolean hasMany() {
for (SqlTreeNode child : children) {
if (child.hasMany()) {
return true;
}
}
return false;
}
}
@@ -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.
* <p>
@@ -146,4 +152,9 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
return null;
}
@Override
public boolean hasMany() {
return manyJoin;
}
}
@@ -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;
}
}
@@ -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 ...
@@ -109,4 +115,9 @@ public class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
// nothing to do here
return null;
}
@Override
public boolean hasMany() {
return true;
}
}
@@ -26,11 +26,19 @@ public final class SqlTreeNodeRoot extends SqlTreeNodeBean {
}
/**
* Construct for raw sql named queries.
* Set AsOf support (at root level).
*/
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, boolean withId) {
super(desc, props, withId, false);
this.includeJoin = null;
public void addAsOfTableAlias(SpiQuery<?> query) {
if (desc.isHistorySupport()) {
query.setAsOfBaseTable();
query.incrementAsOfTableCount();
}
if (lazyLoadParent != null && lazyLoadParent.isManyToManyWithHistory()) {
query.incrementAsOfTableCount();
}
for (int i = 0; i < children.length; i++) {
children[i].addAsOfTableAlias(query);
}
}
/**
@@ -43,6 +43,10 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
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<T> beanType;
private final BeanDescriptor<T> beanDescriptor;
@@ -55,7 +59,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
* 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;
@@ -119,8 +123,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
*/
private ReadEvent futureFetchAudit;
private List<Object> partialIds;
private int timeout;
/**
@@ -146,6 +148,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
private DefaultExpressionList<T> havingExpressions;
private boolean asOfBaseTable;
private int asOfTableCount;
/**
@@ -186,6 +190,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
*/
private boolean forUpdate;
private boolean singleAttribute;
/**
* Set to true if this query has been tuned by autoTune.
*/
@@ -280,6 +286,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return softDeletePredicates;
}
public boolean isAsOfBaseTable() {
return asOfBaseTable;
}
public void setAsOfBaseTable() {
this.asOfBaseTable = true;
}
@Override
public void incrementAsOfTableCount() {
asOfTableCount++;
@@ -520,6 +534,26 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
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;
@@ -561,7 +595,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
public DefaultOrmQuery<T> copy(EbeanServer server) {
DefaultOrmQuery<T> copy = new DefaultOrmQuery<T>(beanDescriptor, server, expressionFactory);
copy.includeTableJoin = includeTableJoin;
copy.m2mIncludeJoin = m2mIncludeJoin;
copy.profilingListener = profilingListener;
// copy.query = query;
@@ -836,7 +870,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
*/
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);
@@ -1003,6 +1037,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return fetch(property, null, null);
}
@Override
public Query<T> fetchQuery(String property) {
return fetch(property, null, FETCH_QUERY);
}
@Override
public Query<T> fetchLazy(String property) {
return fetch(property, null, FETCH_LAZY);
}
@Override
public DefaultOrmQuery<T> fetch(String property, FetchConfig joinConfig) {
return fetch(property, null, joinConfig);
@@ -1013,6 +1057,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return fetch(property, columns, null);
}
@Override
public Query<T> fetchQuery(String property, String columns) {
return fetch(property, columns, FETCH_QUERY);
}
@Override
public Query<T> fetchLazy(String property, String columns) {
return fetch(property, columns, FETCH_LAZY);
}
@Override
public DefaultOrmQuery<T> fetch(String property, String columns, FetchConfig config) {
detail.fetch(property, columns, config);
@@ -1038,11 +1092,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
@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
@@ -1055,6 +1114,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
server.findEach(this, consumer, null);
}
@Override
public QueryIterator<T> findIterate() {
return server.findIterate(this, null);
}
@Override
public List<Version<T>> findVersions() {
this.temporalMode = TemporalMode.VERSIONS;
@@ -1083,15 +1147,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
@Override
public Map<?, T> findMap() {
public <K> Map<K, T> findMap() {
return server.findMap(this, null);
}
@Override
@SuppressWarnings("unchecked")
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
setMapKey(keyProperty);
return (Map<K, T>) findMap();
public <A> List<A> findSingleAttributeList() {
return (List<A>)server.findSingleAttributeList(this, null);
}
@Override
@@ -1109,9 +1172,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return server.findFutureList(this, null);
}
@Override
public FutureRowCount<T> findFutureCount() {
return server.findFutureCount(this, null);
}
@Override
public FutureRowCount<T> findFutureRowCount() {
return server.findFutureRowCount(this, null);
return findFutureCount();
}
@Override
@@ -1244,14 +1312,13 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
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
@@ -1439,16 +1506,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return disableReadAudit;
}
@Override
public List<Object> getIdList() {
return partialIds;
}
@Override
public void setIdList(List<Object> partialIds) {
this.partialIds = partialIds;
}
@Override
public boolean isFutureFetch() {
return futureFetch;
@@ -14,9 +14,8 @@ 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;
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.includeTableJoin = includeTableJoin;
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(includeTableJoin != null ? includeTableJoin.queryHash() : 0);
builder.add(this.m2mIncludeTable);
builder.add(rootTableAlias);
if (detail != null) {
@@ -120,15 +118,12 @@ 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;
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;
}
@@ -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);
}
/**
@@ -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;
@@ -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.
* <p>
* <pre>
* Ebean.beingTransaction();
* Ebean.beginTransaction();
* try {
* // ... perform some actions in a single transaction
*
@@ -110,8 +109,6 @@ public final class DefaultTransactionThreadLocal {
* Ebean.endTransaction();
* }
* </pre>
* <p>
* </p>
*/
public static void end(String serverName) {
@@ -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);
}
/**
@@ -44,11 +43,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;
}
}
@@ -66,6 +66,8 @@ public class JdbcTransaction implements SpiTransaction {
*/
protected boolean active;
protected boolean rollbackOnly;
/**
* The underlying Connection.
*/
@@ -851,33 +853,15 @@ public class JdbcTransaction implements SpiTransaction {
}
}
protected void notifyQueryOnly() {
if (manager != null) {
manager.notifyOfQueryOnly(this);
}
}
/**
* Rollback, Commit or Close for query only transaction.
* <p>
* For a transaction that was used for queries only we can choose to either
* rollback or just close the connection for performance.
* </p>
* 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);
@@ -898,37 +882,73 @@ 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.
* <p>
* This leaves the transaction active and expects another commit
* to occur later (which closes the underlying connection etc).
* </p>
*/
@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.
*/
@Override
public void commit() throws RollbackException {
if (rollbackOnly) {
rollback();
return;
}
if (!isActive()) {
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();
}
performCommit();
flushCommitAndNotify();
}
} catch (Exception e) {
doRollback(e);
throw new RollbackException(e);
} finally {
// these will not throw an exception
firePostCommit();
deactivate();
notifyCommit();
}
}
@@ -945,6 +965,32 @@ 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.
*/
@Override
public void setRollbackOnly() {
this.rollbackOnly = true;
}
/**
* Perform rollback is the transaction is still active.
*/
@Override
public void rollbackIfActive() {
if (isActive()) {
rollback(null);
}
}
/**
* Rollback the transaction.
*/
@@ -962,17 +1008,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);
}
}
@@ -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<TransactionEventListener> transactionEventListeners = bootupClasses.getTransactionEventListeners();
this.transactionEventListeners = transactionEventListeners.toArray(new TransactionEventListener[transactionEventListeners.size()]);
this.prefix = "";
this.externalTransPrefix = "e";
@@ -192,51 +184,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;
}
@@ -344,16 +295,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);
}
for (TransactionEventListener listener : transactionEventListeners) {
listener.postTransactionRollback(transaction, cause);
TXN_LOGGER.debug(msg);
}
} catch (Exception ex) {
@@ -410,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);
}
@@ -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.
* </p>
*/
protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses, ServerConfig serverConfig) {
protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses) {
ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(mode);
@@ -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];
@@ -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;

Some files were not shown because too many files have changed in this diff Show More