Compare commits

...
Author SHA1 Message Date
rbygrave e937d36ca2 [maven-release-plugin] prepare release avaje-ebeanorm-3.4.2 2015-06-19 20:09:51 +12:00
rbygrave 32b7c1a755 Change tests to be more robust 2015-06-19 20:01:00 +12:00
Rob Bygrave c766793f2e Merge pull request #272 from rlamarche/develop-3.3
Backport fix for #154 - @OrderBy on a @OneToMany property is not used when lazy loading
2015-05-08 09:29:28 +12:00
Rob Bygraveandromlam b30b456dbd Fix for #154 - @OrderBy on a @OneToMany property is not used when lazy loading
Conflicts:
	src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
	src/test/java/com/avaje/tests/query/orderby/TestOrderByWithMany.java
2015-04-07 14:09:19 +02:00
Rob Bygrave 6bc86efed7 [maven-release-plugin] prepare for next development iteration 2014-05-28 00:23:27 +12:00
Rob Bygrave 5c447511c1 [maven-release-plugin] prepare release avaje-ebeanorm-3.4.1 2014-05-28 00:23:04 +12:00
Rob Bygrave f91789886c Backport of fix to 3.x for #131 - Memory issue (Hard refs) when using findIterate 2014-05-28 00:21:57 +12:00
Rob Bygrave 7d14ede1b9 [maven-release-plugin] prepare for next development iteration 2014-05-22 20:02:42 +12:00
Rob Bygrave 1ba8bc4557 [maven-release-plugin] prepare release avaje-ebeanorm-3.3.4 2014-05-22 20:02:26 +12:00
Rob Bygrave a234bd1201 Merge pull request #129 from jroper/java16-compat
Backport to JDK 6
2014-05-22 19:36:32 +12:00
James Roper 1c0c0893b6 Backport to JDK 6
Replaced all uses of ju.Objects.hashCode and ju.Objects.equals with a
copy of their implementations inlined into the code.

Also changed source/target for compiler plugin.

To test, I compiled my own avaje launchagent against 6, and changed to
use that in the pom, compiled/tested the whole project using JDK 7,
then ran mvn surefire:test using JDK 6 - running surefire:test ensures
that mvn doesn't try to recompile everything against 6, since that's not
possible because of some of the delegate classes having delegate methods
to JDK 7 jdbc classes.
2014-05-22 15:20:21 +10:00
Rob Bygrave ebbc560ae8 [maven-release-plugin] prepare for next development iteration 2014-05-19 01:03:43 +12:00
Rob Bygrave fcb9df05ad [maven-release-plugin] prepare release avaje-ebeanorm-3.3.3 2014-05-19 01:03:31 +12:00
Rob Bygrave 3de79b211a Change version in pom to 3.3.3-SNAPSHOT in preparation for release 2014-05-19 01:02:13 +12:00
Rob Bygrave d93952a920 Backport of fix for #56 - Using findIterate with MySQL streams 2014-05-19 00:59:05 +12:00
29 changed files with 326 additions and 397 deletions
+2
View File
@@ -7,3 +7,5 @@ target/
logs/ logs/
log/ log/
/mydb.db /mydb.db
*.iml
.idea
+10 -1
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId> <groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId> <artifactId>avaje-ebeanorm</artifactId>
<version>3.3.2</version> <version>3.4.2</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>avaje-ebeanorm</name> <name>avaje-ebeanorm</name>
@@ -167,6 +167,15 @@
<!-- Enhance the meta beans --> <!-- Enhance the meta beans -->
<build> <build>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.avaje.ebeanorm</groupId> <groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId> <artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
@@ -244,14 +244,6 @@ public interface ExpressionList<T> extends Serializable {
*/ */
public Query<T> setMaxRows(int maxRows); public Query<T> setMaxRows(int maxRows);
/**
* Set the number of rows after which the fetching should continue in a
* background thread.
*
* @see Query#setBackgroundFetchAfter(int)
*/
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter);
/** /**
* Set the name of the property which values become the key of a map. * Set the name of the property which values become the key of a map.
* *
@@ -259,15 +251,6 @@ public interface ExpressionList<T> extends Serializable {
*/ */
public Query<T> setMapKey(String mapKey); public Query<T> setMapKey(String mapKey);
/**
* Please migrate to using {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)}.
* Set a QueryListener for bean by bean processing.
*
* @see Query#setListener(QueryListener)
* @deprecated Migrate to {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)}
*/
public Query<T> setListener(QueryListener<T> queryListener);
/** /**
* Set to true to use the query for executing this query. * Set to true to use the query for executing this query.
* *
-37
View File
@@ -663,36 +663,6 @@ public interface Query<T> extends Serializable {
*/ */
public Query<T> setParameter(int position, Object value); public Query<T> setParameter(int position, Object value);
/**
* Please migrate to using {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)}
* <p>
* Set a listener to process the query on a row by row basis.
* </p>
* <p>
* Use this when you want to process a large query and do not want to hold the
* entire query result in memory.
* </p>
* <p>
* It this case the rows are not loaded into the persistence context and
* instead are processed by the query listener.
* </p>
*
* <pre class="code">
* QueryListener&lt;Order&gt; listener = ...;
*
* Query&lt;Order&gt; query = Ebean.createQuery(Order.class);
*
* // set the listener that will process each order one at a time
* query.setListener(listener);
*
* // execute the query. Note that the returned
* // list (emptyList) will be empty ...
* List&lt;Order&gt; emtyList = query.findList();
* </pre>
* @deprecated Deprecated in favor of {@link #findIterate()} and {@link #findVisit(QueryResultVisitor)}
*/
public Query<T> setListener(QueryListener<T> queryListener);
/** /**
* Set the Id value to query. This is used with findUnique(). * Set the Id value to query. This is used with findUnique().
* <p> * <p>
@@ -966,13 +936,6 @@ public interface Query<T> extends Serializable {
*/ */
public Query<T> setMaxRows(int maxRows); public Query<T> setMaxRows(int maxRows);
/**
* Set the rows after which fetching should continue in a background thread.
*
* @param backgroundFetchAfter
*/
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter);
/** /**
* Set the property to use as keys for a map. * Set the property to use as keys for a map.
* <p> * <p>
@@ -1,7 +1,6 @@
package com.avaje.ebean.bean; package com.avaje.ebean.bean;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
/** /**
* Identifies a unique node of an object graph. * Identifies a unique node of an object graph.
@@ -70,7 +69,7 @@ public final class ObjectGraphNode implements Serializable {
public int hashCode() { public int hashCode() {
int hc = 31 * originQueryPoint.hashCode(); int hc = 31 * originQueryPoint.hashCode();
hc = 31 * hc + Objects.hashCode(path); hc = 31 * hc + (path == null ? 0 : path.hashCode());
return hc; return hc;
} }
@@ -83,7 +82,7 @@ public final class ObjectGraphNode implements Serializable {
} }
ObjectGraphNode e = (ObjectGraphNode) obj; ObjectGraphNode e = (ObjectGraphNode) obj;
return Objects.equals(e.path, path) return ((e.path == path) || (e.path != null && e.path.equals(path)))
&& e.originQueryPoint.equals(originQueryPoint); && e.originQueryPoint.equals(originQueryPoint);
} }
} }
@@ -1,7 +1,5 @@
package com.avaje.ebeaninternal.api; package com.avaje.ebeaninternal.api;
import java.util.Objects;
/** /**
* A hash for a query plan. * A hash for a query plan.
*/ */
@@ -26,7 +24,7 @@ public class HashQueryPlan {
public int hashCode() { public int hashCode() {
int hc = planHash; int hc = planHash;
hc = hc * 31 + bindCount; hc = hc * 31 + bindCount;
hc = hc * 31 + Objects.hashCode(rawSql); hc = hc * 31 + (rawSql == null ? 0 : rawSql.hashCode());
return hc; return hc;
} }
@@ -41,6 +39,6 @@ public class HashQueryPlan {
HashQueryPlan e = (HashQueryPlan) obj; HashQueryPlan e = (HashQueryPlan) obj;
return e.planHash == planHash return e.planHash == planHash
&& e.bindCount == bindCount && e.bindCount == bindCount
&& Objects.equals(e.rawSql, rawSql); && ((e.rawSql == rawSql) || (e.rawSql != null && e.rawSql.equals(rawSql)));
} }
} }
@@ -1,7 +1,5 @@
package com.avaje.ebeaninternal.api; package com.avaje.ebeaninternal.api;
import java.util.Objects;
/** /**
* Used to build HashQueryPlan instances. * Used to build HashQueryPlan instances.
*/ */
@@ -33,7 +31,7 @@ public class HashQueryPlanBuilder {
* Add an object to the hash calculation. * Add an object to the hash calculation.
*/ */
public HashQueryPlanBuilder add(Object object) { public HashQueryPlanBuilder add(Object object) {
planHash = planHash * 31 + Objects.hashCode(object); planHash = planHash * 31 + (object == null ? 0 : object.hashCode());
return this; return this;
} }
@@ -6,7 +6,6 @@ import java.util.List;
import com.avaje.ebean.ExpressionList; import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.OrderBy; import com.avaje.ebean.OrderBy;
import com.avaje.ebean.Query; import com.avaje.ebean.Query;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.bean.BeanCollectionTouched; import com.avaje.ebean.bean.BeanCollectionTouched;
import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.CallStack;
import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.bean.EntityBean;
@@ -509,12 +508,6 @@ public interface SpiQuery<T> extends Query<T> {
*/ */
public String getMapKey(); public String getMapKey();
/**
* Return the number of rows after which fetching should occur in a
* background thread.
*/
public int getBackgroundFetchAfter();
/** /**
* Return the maximum number of rows to return in the query. * Return the maximum number of rows to return in the query.
*/ */
@@ -545,19 +538,6 @@ public interface SpiQuery<T> extends Query<T> {
*/ */
public Object getId(); public Object getId();
/**
* Return the queryListener.
*/
public QueryListener<T> getListener();
/**
* Return true if this query should use its own transaction.
* <p>
* This is true for background fetching and when using QueryListener.
* </p>
*/
public boolean createOwnTransaction();
/** /**
* Set the generated sql for debug purposes. * Set the generated sql for debug purposes.
* *
@@ -107,7 +107,10 @@ public class DefaultBeanLoader {
BeanDescriptor<?> desc = ctx.getBeanDescriptor(); BeanDescriptor<?> desc = ctx.getBeanDescriptor();
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(many.getTargetType()); SpiQuery<?> query = (SpiQuery<?>) server.createQuery(many.getTargetType());
String orderBy = many.getLazyFetchOrderBy();
if (orderBy != null) {
query.orderBy(orderBy);
}
query.setLazyLoadForParents(idList, many); query.setLazyLoadForParents(idList, many);
many.addWhereParentIdIn(query, idList); many.addWhereParentIdIn(query, idList);
@@ -90,7 +90,6 @@ import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.el.ElFilter; import com.avaje.ebeaninternal.server.el.ElFilter;
import com.avaje.ebeaninternal.server.jmx.MAdminAutofetch; import com.avaje.ebeaninternal.server.jmx.MAdminAutofetch;
import com.avaje.ebeaninternal.server.lib.ShutdownManager; import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
import com.avaje.ebeaninternal.server.query.CQuery; import com.avaje.ebeaninternal.server.query.CQuery;
import com.avaje.ebeaninternal.server.query.CQueryEngine; import com.avaje.ebeaninternal.server.query.CQueryEngine;
import com.avaje.ebeaninternal.server.query.CallableQueryIds; import com.avaje.ebeaninternal.server.query.CallableQueryIds;
@@ -1133,7 +1132,7 @@ public final class DefaultServer implements SpiEbeanServer {
if (Mode.LAZYLOAD_MANY.equals(query.getMode())) { if (Mode.LAZYLOAD_MANY.equals(query.getMode())) {
allowOneManyFetch = false; allowOneManyFetch = false;
} else if (query.hasMaxRowsOrFirstRow() && !query.isRawSql() && !query.isSqlSelect() && query.getBackgroundFetchAfter() == 0) { } else if (query.hasMaxRowsOrFirstRow() && !query.isRawSql() && !query.isSqlSelect()) {
// convert ALL fetch joins to Many's to be query joins // convert ALL fetch joins to Many's to be query joins
// so that limit offset type SQL clauses work // so that limit offset type SQL clauses work
allowOneManyFetch = false; allowOneManyFetch = false;
@@ -1194,16 +1193,15 @@ public final class DefaultServer implements SpiEbeanServer {
if (cachedBean != null) { if (cachedBean != null) {
if (context == null) { if (context == null) {
context = new DefaultPersistenceContext(); context = new DefaultPersistenceContext();
} }
context.put(query.getId(), cachedBean);
DLoadContext loadContext = new DLoadContext(this, beanDescriptor, query.isReadOnly(), query); // Not using a loadContext for beans coming out of L2 cache
loadContext.setPersistenceContext(context); // so that means no batch lazy loading for these beans
EntityBean entityBean = (EntityBean) cachedBean;
EntityBeanIntercept ebi = ((EntityBean) cachedBean)._ebean_getIntercept(); EntityBeanIntercept ebi = entityBean._ebean_getIntercept();
ebi.setPersistenceContext(context); ebi.setPersistenceContext(context);
loadContext.register(null, ebi); Object id = beanDescriptor.getId(entityBean);
context.put(id, entityBean);
} }
return (T) cachedBean; return (T) cachedBean;
@@ -29,6 +29,7 @@ import com.avaje.ebeaninternal.server.deploy.DeployPropertyParserMap;
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext; import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
import com.avaje.ebeaninternal.server.query.CQueryPlan; import com.avaje.ebeaninternal.server.query.CQueryPlan;
import com.avaje.ebeaninternal.server.query.CancelableQuery; import com.avaje.ebeaninternal.server.query.CancelableQuery;
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
/** /**
* Wraps the objects involved in executing a Query. * Wraps the objects involved in executing a Query.
@@ -43,7 +44,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
private final BeanFinder<T> finder; private final BeanFinder<T> finder;
private final LoadContext graphContext; private LoadContext graphContext;
private final Boolean readOnly; private final Boolean readOnly;
@@ -75,9 +76,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
this.queryEngine = queryEngine; this.queryEngine = queryEngine;
this.query = query; this.query = query;
this.readOnly = query.isReadOnly(); this.readOnly = query.isReadOnly();
this.graphContext = new DLoadContext(ebeanServer, beanDescriptor, readOnly, query);
graphContext.registerSecondaryQueries(query);
} }
public void executeSecondaryQueries(int defaultQueryBatch) { public void executeSecondaryQueries(int defaultQueryBatch) {
@@ -163,12 +161,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
@Override @Override
public void initTransIfRequired() { public void initTransIfRequired() {
// first check if the query requires its own transaction // first check if the query requires its own transaction
if (query.createOwnTransaction()) { if (transaction == null) {
// using background fetch or query listener etc
transaction = ebeanServer.createQueryTransaction();
createdTransaction = true;
} else if (transaction == null) {
// maybe a current one // maybe a current one
transaction = ebeanServer.getCurrentServerTransaction(); transaction = ebeanServer.getCurrentServerTransaction();
if (transaction == null) { if (transaction == null) {
@@ -177,8 +170,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
createdTransaction = true; createdTransaction = true;
} }
} }
this.persistenceContext = getPersistenceContext(query, transaction); this.persistenceContext = getPersistenceContext(query, transaction);
this.graphContext.setPersistenceContext(persistenceContext);
this.graphContext = new DLoadContext(this);
this.graphContext.registerSecondaryQueries(query);
} }
/** /**
@@ -381,7 +377,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
} }
public void flushPersistenceContextOnIterate() { public void flushPersistenceContextOnIterate() {
beanDescriptor.flushPersistenceContextOnIterate(persistenceContext); persistenceContext = new DefaultPersistenceContext();
graphContext.setPersistenceContext(persistenceContext);
} }
} }
@@ -2445,12 +2445,4 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
return false; return false;
} }
public void flushPersistenceContextOnIterate(PersistenceContext persistenceContext) {
persistenceContext.clear(beanType);
for (int i = 0; i < propertiesMany.length; i++) {
persistenceContext.clear(propertiesMany[i].getBeanDescriptor().getBeanType());
}
}
} }
@@ -54,9 +54,17 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
*/ */
final boolean manyToMany; final boolean manyToMany;
final String fetchOrderBy; /**
* Order by used when fetch joining the associated many.
*/
private final String fetchOrderBy;
final String mapKey; /**
* Order by used when lazy loading the associated many.
*/
private String lazyFetchOrderBy;
private final String mapKey;
/** /**
* The type of the many, set, list or map. * The type of the many, set, list or map.
@@ -132,6 +140,22 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
exportedProperties = createExported(); exportedProperties = createExported();
if (exportedProperties.length > 0){ if (exportedProperties.length > 0){
embeddedExportedProperties = exportedProperties[0].isEmbedded(); embeddedExportedProperties = exportedProperties[0].isEmbedded();
if (fetchOrderBy != null) {
// derive lazyFetchOrderBy
StringBuilder sb = new StringBuilder(50);
for (int i = 0; i < exportedProperties.length; i++) {
if (i > 0) {
sb.append(", ");
}
// these fkcolumns always on base table hence t0 as alias
sb.append("t0.").append(exportedProperties[i].getForeignDbColumn());
}
if (fetchOrderBy != null) {
sb.append(", ").append(fetchOrderBy);
}
lazyFetchOrderBy = sb.toString().trim();
}
} }
String delStmt; String delStmt;
@@ -462,6 +486,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
} }
/** /**
* Return the order by for use when lazy loading the associated collection.
*/
public String getLazyFetchOrderBy() {
return lazyFetchOrderBy;
}
/**
* Return the default mapKey when returning a Map. * Return the default mapKey when returning a Map.
*/ */
public String getMapKey() { public String getMapKey() {
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.expression;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebean.event.BeanQueryRequest;
@@ -115,7 +114,7 @@ class AllEqualsExpression implements SpiExpression {
int hc = 31; int hc = 31;
for (Object value : propMap.values()) { for (Object value : propMap.values()) {
hc = hc * 31 + Objects.hashCode(value); hc = hc * 31 + (value == null ? 0 : value.hashCode());
} }
return hc; return hc;
@@ -14,7 +14,6 @@ import com.avaje.ebean.Junction;
import com.avaje.ebean.OrderBy; import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PagingList; import com.avaje.ebean.PagingList;
import com.avaje.ebean.QueryIterator; import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder; import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
@@ -375,19 +374,10 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
return exprList.select(properties); return exprList.select(properties);
} }
public com.avaje.ebean.Query<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
return exprList.setBackgroundFetchAfter(backgroundFetchAfter);
}
public com.avaje.ebean.Query<T> setFirstRow(int firstRow) { public com.avaje.ebean.Query<T> setFirstRow(int firstRow) {
return exprList.setFirstRow(firstRow); return exprList.setFirstRow(firstRow);
} }
@Deprecated
public com.avaje.ebean.Query<T> setListener(QueryListener<T> queryListener) {
return exprList.setListener(queryListener);
}
public com.avaje.ebean.Query<T> setMapKey(String mapKey) { public com.avaje.ebean.Query<T> setMapKey(String mapKey) {
return exprList.setMapKey(mapKey); return exprList.setMapKey(mapKey);
} }
@@ -28,8 +28,9 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
super(parent, desc, path, defaultBatchSize, 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); this.currentBuffer = createBuffer(firstBatchSize);
this.bufferList = queryFetch ? new ArrayList<DLoadBeanContext.LoadBuffer>() : null;
} }
protected void configureQuery(SpiQuery<?> query, String lazyLoadProperty) { protected void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
@@ -51,11 +52,11 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
protected void register(EntityBeanIntercept ebi){ protected void register(EntityBeanIntercept ebi){
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext()); if (currentBuffer.isFull()) {
if (currentBuffer.add(ebi)) {
// the currentBuffer is full so create another one
currentBuffer = createBuffer(secondaryBatchSize); currentBuffer = createBuffer(secondaryBatchSize);
} }
currentBuffer.add(ebi);
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext());
} }
private LoadBuffer createBuffer(int size) { private LoadBuffer createBuffer(int size) {
@@ -98,22 +99,29 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
*/ */
public static class LoadBuffer implements BeanLoader, LoadBeanBuffer { public static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
private final PersistenceContext persistenceContext;
private final DLoadBeanContext context; private final DLoadBeanContext context;
private final int batchSize; private final int batchSize;
private final List<EntityBeanIntercept> list; private final List<EntityBeanIntercept> list;
public LoadBuffer(DLoadBeanContext context, int batchSize) { public LoadBuffer(DLoadBeanContext context, int batchSize) {
this.context = context; this.context = context;
// set the persistence context as at this moment in
// case it changes as part of a findIterate etc
this.persistenceContext = context.getPersistenceContext();
this.batchSize = batchSize; this.batchSize = batchSize;
this.list = new ArrayList<EntityBeanIntercept>(batchSize); this.list = new ArrayList<EntityBeanIntercept>(batchSize);
} }
public boolean isFull() {
return batchSize == list.size();
}
/** /**
* Return true if the buffer is full. * Return true if the buffer is full.
*/ */
public boolean add(EntityBeanIntercept ebi) { public void add(EntityBeanIntercept ebi) {
list.add(ebi); list.add(ebi);
return batchSize == list.size();
} }
@Override @Override
@@ -138,7 +146,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
@Override @Override
public PersistenceContext getPersistenceContext() { public PersistenceContext getPersistenceContext() {
return context.getPersistenceContext(); return persistenceContext;
} }
@Override @Override
@@ -52,12 +52,14 @@ public class DLoadContext implements LoadContext {
private List<OrmQueryProperties> secQuery; private List<OrmQueryProperties> secQuery;
public DLoadContext(SpiEbeanServer ebeanServer, BeanDescriptor<?> rootDescriptor, Boolean readOnly, SpiQuery<?> query) { public DLoadContext(OrmQueryRequest<?> request) {
this.ebeanServer = ebeanServer; this.persistenceContext = request.getPersistenceContext();
this.ebeanServer = request.getServer();
this.defaultBatchSize = ebeanServer.getLazyLoadBatchSize(); this.defaultBatchSize = ebeanServer.getLazyLoadBatchSize();
this.rootDescriptor = rootDescriptor; this.rootDescriptor = request.getBeanDescriptor();
this.readOnly = readOnly; SpiQuery<?> query = request.getQuery();
this.readOnly = query.isReadOnly();
this.excludeBeanCache = Boolean.FALSE.equals(query.isUseBeanCache()); this.excludeBeanCache = Boolean.FALSE.equals(query.isUseBeanCache());
this.useAutofetchManager = query.getAutoFetchManager() != null; this.useAutofetchManager = query.getAutoFetchManager() != null;
@@ -24,63 +24,64 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
private LoadBuffer currentBuffer; private LoadBuffer currentBuffer;
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property, public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property, String path, int defaultBatchSize,
String path, int defaultBatchSize, OrmQueryProperties queryProps) { OrmQueryProperties queryProps) {
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps); super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
this.property = property; this.property = property;
this.bufferList = new ArrayList<DLoadManyContext.LoadBuffer>(); // bufferList only required when using query joins (queryFetch)
this.bufferList = (!queryFetch) ? null : new ArrayList<DLoadManyContext.LoadBuffer>();
this.currentBuffer = createBuffer(firstBatchSize); this.currentBuffer = createBuffer(firstBatchSize);
} }
private LoadBuffer createBuffer(int size) { private LoadBuffer createBuffer(int size) {
LoadBuffer buffer = new LoadBuffer(this, size); LoadBuffer buffer = new LoadBuffer(this, size);
bufferList.add(buffer); if (bufferList != null) {
bufferList.add(buffer);
}
return buffer; return buffer;
} }
public void configureQuery(SpiQuery<?> query){ public void configureQuery(SpiQuery<?> query) {
// propagate the readOnly state // propagate the readOnly state
if (parent.isReadOnly() != null){ if (parent.isReadOnly() != null) {
query.setReadOnly(parent.isReadOnly()); query.setReadOnly(parent.isReadOnly());
} }
query.setParentNode(objectGraphNode); query.setParentNode(objectGraphNode);
if (queryProps != null){ if (queryProps != null) {
queryProps.configureBeanQuery(query); queryProps.configureBeanQuery(query);
} }
if (parent.isUseAutofetchManager()){ if (parent.isUseAutofetchManager()) {
query.setAutofetch(true); query.setAutofetch(true);
} }
} }
public BeanPropertyAssocMany<?> getBeanProperty() { public BeanPropertyAssocMany<?> getBeanProperty() {
return property; return property;
} }
public BeanDescriptor<?> getBeanDescriptor() { public BeanDescriptor<?> getBeanDescriptor() {
return desc; return desc;
} }
public String getName() {
return parent.getEbeanServer().getName();
}
public String getName() { public void register(BeanCollection<?> bc) {
return parent.getEbeanServer().getName();
}
public void register(BeanCollection<?> bc){ if (currentBuffer.isFull()) {
bc.setLoader(0, currentBuffer);
if (currentBuffer.add(bc)) {
// the currentBuffer is full so create another one
currentBuffer = createBuffer(secondaryBatchSize); currentBuffer = createBuffer(secondaryBatchSize);
} }
} currentBuffer.add(bc);
bc.setLoader(0, currentBuffer);
}
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all) {
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all){
if (!queryFetch) { if (!queryFetch) {
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?"); throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
@@ -89,7 +90,8 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
if (bufferList != null) { if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) { for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) { if (!loadBuffer.list.isEmpty()) {
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest.getTransaction(), requestedBatchSize, false, false, false); LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest.getTransaction(), requestedBatchSize,
false, false, false);
parent.getEbeanServer().loadMany(req); parent.getEbeanServer().loadMany(req);
if (!queryProps.isQueryFetchAll()) { if (!queryProps.isQueryFetchAll()) {
// Stop - only fetch the first batch ... the rest will be lazy loaded // Stop - only fetch the first batch ... the rest will be lazy loaded
@@ -102,20 +104,24 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
this.bufferList = null; this.bufferList = null;
} }
} }
} }
/** /**
* A buffer for batch loading bean collections on a given path. * A buffer for batch loading bean collections on a given path. Supports batch lazy loading and
* Supports batch lazy loading and secondary query loading. * secondary query loading.
*/ */
public static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer { public static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
private final PersistenceContext persistenceContext;
private final DLoadManyContext context; private final DLoadManyContext context;
private final int batchSize; private final int batchSize;
private final List<BeanCollection<?>> list; private final List<BeanCollection<?>> list;
public LoadBuffer(DLoadManyContext context, int batchSize) { public LoadBuffer(DLoadManyContext context, int batchSize) {
this.context = context; this.context = context;
// set the persistence context as at this moment in
// case it changes as part of a findIterate etc
this.persistenceContext = context.getPersistenceContext();
this.batchSize = batchSize; this.batchSize = batchSize;
this.list = new ArrayList<BeanCollection<?>>(batchSize); this.list = new ArrayList<BeanCollection<?>>(batchSize);
} }
@@ -123,11 +129,17 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
/** /**
* Return true if the buffer is full. * Return true if the buffer is full.
*/ */
public boolean add(BeanCollection<?> bc) { public boolean isFull() {
list.add(bc);
return batchSize == list.size(); return batchSize == list.size();
} }
/**
* Return true if the buffer is full.
*/
public void add(BeanCollection<?> bc) {
list.add(bc);
}
@Override @Override
public List<BeanCollection<?>> getBatch() { public List<BeanCollection<?>> getBatch() {
return list; return list;
@@ -144,7 +156,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
} }
@Override @Override
public void configureQuery(SpiQuery<?> query){ public void configureQuery(SpiQuery<?> query) {
context.configureQuery(query); context.configureQuery(query);
} }
@@ -160,7 +172,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
@Override @Override
public PersistenceContext getPersistenceContext() { public PersistenceContext getPersistenceContext() {
return context.getPersistenceContext(); return persistenceContext;
} }
@Override @Override
@@ -183,7 +195,8 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
} }
} }
// Should reduce the list by checking each beanCollection in the L2 first before executing the query // Should reduce the list by checking each beanCollection in the L2 first before executing
// the query
LoadManyRequest req = new LoadManyRequest(this, null, batchSize, true, onlyIds, useCache); LoadManyRequest req = new LoadManyRequest(this, null, batchSize, true, onlyIds, useCache);
context.parent.getEbeanServer().loadMany(req); context.parent.getEbeanServer().loadMany(req);
@@ -14,7 +14,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.avaje.ebean.QueryIterator; import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionAdd; import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.bean.EntityBean;
@@ -24,7 +23,6 @@ import com.avaje.ebean.bean.NodeUsageListener;
import com.avaje.ebean.bean.ObjectGraphNode; import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.LoadContext; import com.avaje.ebeaninternal.api.LoadContext;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiExpressionList; import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Mode; import com.avaje.ebeaninternal.api.SpiQuery.Mode;
@@ -41,7 +39,6 @@ import com.avaje.ebeaninternal.server.deploy.DbReadContext;
import com.avaje.ebeaninternal.server.el.ElPropertyValue; import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.lib.util.StringHelper; import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties; import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
import com.avaje.ebeaninternal.server.type.DataBind; import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.DataReader; import com.avaje.ebeaninternal.server.type.DataReader;
@@ -135,8 +132,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
private final SpiQuery<T> query; private final SpiQuery<T> query;
private final QueryListener<T> queryListener;
private Map<String, String> currentPathMap; private Map<String, String> currentPathMap;
private String currentPrefix; private String currentPrefix;
@@ -189,8 +184,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
*/ */
private final ElPropertyValue manyPropertyEl; private final ElPropertyValue manyPropertyEl;
private final int backgroundFetchAfter;
private final int maxRowsLimit; private final int maxRowsLimit;
/** /**
@@ -198,8 +191,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
*/ */
private boolean hasHitBackgroundFetchAfter; private boolean hasHitBackgroundFetchAfter;
private final PersistenceContext persistenceContext;
private DataReader dataReader; private DataReader dataReader;
/** /**
@@ -276,20 +267,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
this.desc = request.getBeanDescriptor(); this.desc = request.getBeanDescriptor();
this.predicates = predicates; this.predicates = predicates;
this.queryListener = query.getListener();
if (queryListener == null) {
// normal, use the one from the transaction
this.persistenceContext = request.getPersistenceContext();
} else {
// 'Row Level Transaction Context'...
// local transaction context that will be reset
// after each 'master' bean is sent to the listener
this.persistenceContext = new DefaultPersistenceContext();
}
this.maxRowsLimit = query.getMaxRows() > 0 ? query.getMaxRows() : GLOBAL_ROW_LIMIT; this.maxRowsLimit = query.getMaxRows() > 0 ? query.getMaxRows() : GLOBAL_ROW_LIMIT;
this.backgroundFetchAfter = query.getBackgroundFetchAfter() > 0 ? query
.getBackgroundFetchAfter() : Integer.MAX_VALUE;
this.help = createHelp(request); this.help = createHelp(request);
this.collection = (BeanCollection<T>) (help != null ? help.createEmpty(false) : null); this.collection = (BeanCollection<T>) (help != null ? help.createEmpty(false) : null);
@@ -386,6 +364,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
if (forwardOnlyHint) { if (forwardOnlyHint) {
// Use forward only hints for large resultset processing (Issue 56, MySql specific) // Use forward only hints for large resultset processing (Issue 56, MySql specific)
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
pstmt.setFetchSize(Integer.MIN_VALUE);
} else { } else {
pstmt = conn.prepareStatement(sql); pstmt = conn.prepareStatement(sql);
} }
@@ -442,7 +421,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
* Return the persistence context. * Return the persistence context.
*/ */
public PersistenceContext getPersistenceContext() { public PersistenceContext getPersistenceContext() {
return persistenceContext; return request.getPersistenceContext();
} }
public void setLoadedBean(Object bean, Object id, Object lazyLoadParentId) { public void setLoadedBean(Object bean, Object id, Object lazyLoadParentId) {
@@ -465,7 +444,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
if (lazyLoadParentId != null) { if (lazyLoadParentId != null) {
if (!lazyLoadParentId.equals(this.lazyLoadParentId)) { if (!lazyLoadParentId.equals(this.lazyLoadParentId)) {
// get the appropriate parent bean from the persistence context // get the appropriate parent bean from the persistence context
this.lazyLoadParentBean = persistenceContext.get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId); this.lazyLoadParentBean = getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
this.lazyLoadParentId = lazyLoadParentId; this.lazyLoadParentId = lazyLoadParentId;
} }
@@ -563,12 +542,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
return false; return false;
} }
if (inForeground && loadedBeanCount >= backgroundFetchAfter) {
hasHitBackgroundFetchAfter = true;
collection.setFinishedFetch(false);
return false;
}
if (!manyIncluded) { if (!manyIncluded) {
// simple query... no details... // simple query... no details...
return readRow(); return readRow();
@@ -686,13 +659,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
private void readTheRows(boolean inForeground) throws SQLException { private void readTheRows(boolean inForeground) throws SQLException {
while (hasNextBean(inForeground)) { while (hasNextBean(inForeground)) {
if (queryListener != null) { // add to the list/set/map
queryListener.process(getLoadedBean()); help.add(collection, getLoadedBean());
} else {
// add to the list/set/map
help.add(collection, getLoadedBean());
}
} }
} }
@@ -73,7 +73,6 @@ public class CQueryFetchIds {
private int rowCount; private int rowCount;
private final int maxRows; private final int maxRows;
private final int bgFetchAfter;
/** /**
* Create the Sql select based on the request. * Create the Sql select based on the request.
@@ -86,7 +85,6 @@ public class CQueryFetchIds {
this.query = request.getQuery(); this.query = request.getQuery();
this.sql = sql; this.sql = sql;
this.maxRows = query.getMaxRows(); this.maxRows = query.getMaxRows();
this.bgFetchAfter = query.getBackgroundFetchAfter();
query.setGeneratedSql(sql); query.setGeneratedSql(sql);
@@ -184,9 +182,6 @@ public class CQueryFetchIds {
hasMoreRows = rset.next(); hasMoreRows = rset.next();
break; break;
} else if (bgFetchAfter > 0 && rowCount >= bgFetchAfter) {
useBackgroundToContinueFetch = true;
break;
} }
} }
@@ -21,7 +21,6 @@ import com.avaje.ebean.OrderBy.Property;
import com.avaje.ebean.PagingList; import com.avaje.ebean.PagingList;
import com.avaje.ebean.Query; import com.avaje.ebean.Query;
import com.avaje.ebean.QueryIterator; import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.RawSql; import com.avaje.ebean.RawSql;
import com.avaje.ebean.bean.BeanCollectionTouched; import com.avaje.ebean.bean.BeanCollectionTouched;
@@ -69,8 +68,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
*/ */
private transient ArrayList<EntityBean> contextAdditions; private transient ArrayList<EntityBean> contextAdditions;
private transient QueryListener<T> queryListener;
/** /**
* For lazy loading of ManyToMany we need to add a join to the intersection * For lazy loading of ManyToMany we need to add a join to the intersection
* table. This is that join to the intersection table. * table. This is that join to the intersection table.
@@ -143,11 +140,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
private List<Object> partialIds; private List<Object> partialIds;
/**
* The rows after which the fetch continues in a bg thread.
*/
private int backgroundFetchAfter;
private int timeout = -1; private int timeout = -1;
/** /**
@@ -437,7 +429,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
copy.additionalWhere = additionalWhere; copy.additionalWhere = additionalWhere;
copy.additionalHaving = additionalHaving; copy.additionalHaving = additionalHaving;
copy.distinct = distinct; copy.distinct = distinct;
copy.backgroundFetchAfter = backgroundFetchAfter;
copy.timeout = timeout; copy.timeout = timeout;
copy.mapKey = mapKey; copy.mapKey = mapKey;
copy.id = id; copy.id = id;
@@ -1016,26 +1007,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return this; return this;
} }
/**
* Return the findListener is one has been set.
*/
public QueryListener<T> getListener() {
return queryListener;
}
/**
* Set a FindListener. This is designed for large fetches where lots are
* rows are to be processed and instead of returning all the rows they are
* processed one at a time.
* <p>
* Note that the returning List Set or Map will be empty.
* </p>
*/
public DefaultOrmQuery<T> setListener(QueryListener<T> queryListener) {
this.queryListener = queryListener;
return this;
}
public Class<T> getBeanType() { public Class<T> getBeanType() {
return beanType; return beanType;
} }
@@ -1112,15 +1083,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return this; return this;
} }
public int getBackgroundFetchAfter() {
return backgroundFetchAfter;
}
public DefaultOrmQuery<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
this.backgroundFetchAfter = backgroundFetchAfter;
return this;
}
public Object getId() { public Object getId() {
return id; return id;
} }
@@ -1235,23 +1197,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return whereExpressions; return whereExpressions;
} }
/**
* Return true if using background fetching or a queryListener.
*/
public boolean createOwnTransaction() {
if (futureFetch){
// the future fetches have already created
// their own transaction
return false;
}
if (backgroundFetchAfter > 0 || queryListener != null) {
// run in own transaction as we can't know how long
// the background fetching will continue etc
return true;
}
return false;
}
public String getGeneratedSql() { public String getGeneratedSql() {
return generatedSql; return generatedSql;
} }
@@ -17,7 +17,6 @@ import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PagingList; import com.avaje.ebean.PagingList;
import com.avaje.ebean.Query; import com.avaje.ebean.Query;
import com.avaje.ebean.QueryIterator; import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryListener;
import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder; import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
@@ -213,19 +212,10 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.setMaxRows(maxRows); return query.setMaxRows(maxRows);
} }
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
return query.setBackgroundFetchAfter(backgroundFetchAfter);
}
public Query<T> setMapKey(String mapKey) { public Query<T> setMapKey(String mapKey) {
return query.setMapKey(mapKey); return query.setMapKey(mapKey);
} }
@Deprecated
public Query<T> setListener(QueryListener<T> queryListener) {
return query.setListener(queryListener);
}
public Query<T> setUseCache(boolean useCache) { public Query<T> setUseCache(boolean useCache) {
return query.setUseCache(useCache); return query.setUseCache(useCache);
} }
@@ -14,7 +14,6 @@ import com.avaje.ebean.FutureRowCount;
import com.avaje.ebean.OrderBy; import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PagingList; import com.avaje.ebean.PagingList;
import com.avaje.ebean.Query; import com.avaje.ebean.Query;
import com.avaje.ebean.QueryListener;
import com.avaje.ebeaninternal.api.SpiExpressionList; import com.avaje.ebeaninternal.api.SpiExpressionList;
import com.avaje.ebeaninternal.server.expression.FilterExprPath; import com.avaje.ebeaninternal.server.expression.FilterExprPath;
@@ -128,19 +127,10 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
throw new PersistenceException(notAllowedMessage); throw new PersistenceException(notAllowedMessage);
} }
public Query<T> setBackgroundFetchAfter(int backgroundFetchAfter) {
return rootQuery.setBackgroundFetchAfter(backgroundFetchAfter);
}
public Query<T> setFirstRow(int firstRow) { public Query<T> setFirstRow(int firstRow) {
return rootQuery.setFirstRow(firstRow); return rootQuery.setFirstRow(firstRow);
} }
@Deprecated
public Query<T> setListener(QueryListener<T> queryListener) {
return rootQuery.setListener(queryListener);
}
public Query<T> setMapKey(String mapKey) { public Query<T> setMapKey(String mapKey) {
return rootQuery.setMapKey(mapKey); return rootQuery.setMapKey(mapKey);
} }
@@ -1,63 +0,0 @@
package com.avaje.tests.basic;
import junit.framework.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.tests.model.basic.Order;
import com.avaje.tests.model.basic.ResetBasicData;
public class TestBackgroundFetchAfter extends BaseTestCase {
@Test
public void testWrtJoin() {
ResetBasicData.reset();
SpiEbeanServer server = (SpiEbeanServer)Ebean.getServer(null);
boolean h2Db = "h2".equals(server.getDatabasePlatform().getName());
// limit not in sql as join to many
Query<Order> q = Ebean.find(Order.class)
.fetch("details")
.setBackgroundFetchAfter(3)
.setMaxRows(10);
q.findList();
String sql = q.getGeneratedSql();
if (h2Db){
Assert.assertTrue(sql.indexOf("limit") == -1);
}
// allows limit use as no join to many
q = Ebean.find(Order.class)
.setBackgroundFetchAfter(3)
.setMaxRows(10);
q.findList();
sql = q.getGeneratedSql();
if (h2Db){
Assert.assertTrue(sql.indexOf("limit") > -1);
}
// allows limit use as join to one (not many)
q = Ebean.find(Order.class)
.fetch("customer")
.setBackgroundFetchAfter(3)
.setMaxRows(10);
q.findList();
sql = q.getGeneratedSql();
if (h2Db){
Assert.assertTrue(sql.indexOf("limit") > -1);
}
}
}
@@ -1,5 +1,6 @@
package com.avaje.tests.basic; package com.avaje.tests.basic;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import junit.framework.Assert; import junit.framework.Assert;
@@ -29,8 +30,13 @@ public class TestInheritRef extends BaseTestCase {
t.setCapacity(20D); t.setCapacity(20D);
Ebean.save(t); Ebean.save(t);
List<Integer> ids = new ArrayList<Integer>();
ids.add(c.getId());
ids.add(t.getId());
List<Vehicle> list = Ebean.find(Vehicle.class) List<Vehicle> list = Ebean.find(Vehicle.class)
.setAutofetch(false) .setAutofetch(false)
.where().idIn(ids)
.findList(); .findList();
Assert.assertTrue(list.size() > 0); Assert.assertTrue(list.size() > 0);
@@ -39,7 +45,6 @@ public class TestInheritRef extends BaseTestCase {
Truck truck = (Truck)vehicle; Truck truck = (Truck)vehicle;
Assert.assertTrue(truck.getLicenseNumber().equals("T1098")); Assert.assertTrue(truck.getLicenseNumber().equals("T1098"));
Assert.assertTrue(truck.getCapacity() == 20D); Assert.assertTrue(truck.getCapacity() == 20D);
} }
} }
@@ -3,6 +3,8 @@ package com.avaje.tests.basic;
import java.sql.Date; import java.sql.Date;
import java.util.List; import java.util.List;
import com.avaje.ebean.cache.ServerCache;
import com.avaje.ebean.cache.ServerCacheManager;
import junit.framework.Assert; import junit.framework.Assert;
import org.junit.Test; import org.junit.Test;
@@ -20,6 +22,9 @@ public class TestManyLazyLoad extends BaseTestCase {
ResetBasicData.reset(); ResetBasicData.reset();
ServerCacheManager serverCacheManager = Ebean.getServerCacheManager();
serverCacheManager.clearAll();
List<Order> list = Ebean.find(Order.class).order().asc("id").findList(); List<Order> list = Ebean.find(Order.class).order().asc("id").findList();
Assert.assertTrue(list.size()+" > 0", list.size() > 0); Assert.assertTrue(list.size()+" > 0", list.size() > 0);
@@ -40,8 +45,7 @@ public class TestManyLazyLoad extends BaseTestCase {
Assert.assertTrue(sz+" > 0", sz > 0); Assert.assertTrue(sz+" > 0", sz > 0);
Order o = details.get(0).getOrder(); Order o = details.get(0).getOrder();
Assert.assertTrue("same instance", o == order1); Assert.assertSame("same instance", o, order1);
// change order... list before a scalar property // change order... list before a scalar property
Order order2 = Ebean.getReference(Order.class, order.getId()); Order order2 = Ebean.getReference(Order.class, order.getId());
@@ -2,8 +2,7 @@ package com.avaje.tests.basic;
import java.util.List; import java.util.List;
import junit.framework.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.BaseTestCase;
@@ -25,6 +24,8 @@ public class TestSharedInstancePropagation extends BaseTestCase {
ResetBasicData.reset(); ResetBasicData.reset();
Ebean.getServerCacheManager().clearAll();
Order order = Ebean.find(Order.class) Order order = Ebean.find(Order.class)
.setAutofetch(false) .setAutofetch(false)
.setUseCache(true) .setUseCache(true)
@@ -1,5 +1,8 @@
package com.avaje.tests.query.orderby; package com.avaje.tests.query.orderby;
import java.util.List;
import org.avaje.ebeantest.LoggedSqlCollector;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@@ -7,6 +10,7 @@ import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean; import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query; import com.avaje.ebean.Query;
import com.avaje.tests.model.basic.Order; import com.avaje.tests.model.basic.Order;
import com.avaje.tests.model.basic.OrderDetail;
import com.avaje.tests.model.basic.ResetBasicData; import com.avaje.tests.model.basic.ResetBasicData;
public class TestOrderByWithMany extends BaseTestCase { public class TestOrderByWithMany extends BaseTestCase {
@@ -16,6 +20,8 @@ public class TestOrderByWithMany extends BaseTestCase {
ResetBasicData.reset(); ResetBasicData.reset();
checkWithLazyLoadingOnBuiltInMany();
checkWithBuiltInManyBasic();
checkWithBuiltInMany(); checkWithBuiltInMany();
checkAppendId(); checkAppendId();
checkNone(); checkNone();
@@ -25,6 +31,42 @@ public class TestOrderByWithMany extends BaseTestCase {
checkAlreadyIncluded2(); checkAlreadyIncluded2();
} }
private void checkWithLazyLoadingOnBuiltInMany() {
LoggedSqlCollector.start();
Query<Order> query = Ebean.find(Order.class);
// a query that ensures we are going to lazy load on the details
List<Order> orders = query.findList();
for (Order order : orders) {
// invoke lazy loading
List<OrderDetail> details = order.getDetails();
details.size();
}
// first one is the main query and others are lazy loading queries
List<String> loggedSql = LoggedSqlCollector.stop();
Assert.assertTrue(loggedSql.size() > 1);
String lazyLoadSql = loggedSql.get(1);
// contains the foreign key back to the parent bean (t0.order_id)
Assert.assertTrue(lazyLoadSql.contains("select t0.order_id c0, t0.id"));
Assert.assertTrue(lazyLoadSql.contains("order by t0.order_id, t0.id, t0.order_qty, t0.cretime desc"));
}
private void checkWithBuiltInManyBasic() {
Query<Order> query = Ebean.find(Order.class).fetch("details");
query.findList();
String sql = query.getGeneratedSql();
Assert.assertTrue(sql.contains("order by t0.id, t1.id asc, t1.order_qty asc, t1.cretime desc"));
}
private void checkWithBuiltInMany() { private void checkWithBuiltInMany() {
Query<Order> query = Ebean.find(Order.class).fetch("details").order().desc("customer.name"); Query<Order> query = Ebean.find(Order.class).fetch("details").order().desc("customer.name");
@@ -0,0 +1,87 @@
package org.avaje.ebeantest;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
/**
* Helper that can collect the SQL that is logged via SLF4J.
* <p>
* Used {@link #start()} and {@link #stop()} to collect the logged messages that contain the
* executed SQL statements.
* <p>
* Internally this uses a Logback Appender to collect messages for org.avaje.ebean.SQL.
*/
public class LoggedSqlCollector {
private static BasicAppender basicAppender = new BasicAppender();
static {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
basicAppender.setContext(lc);
Logger logger = (Logger) LoggerFactory.getLogger("org.avaje.ebean.SQL");
logger.addAppender(basicAppender);
logger.setLevel(Level.TRACE);
logger.setAdditive(true);
}
/**
* Start collection of the logged SQL statements.
*/
public static List<String> start() {
return basicAppender.collectStart();
}
/**
* Stop collection of the logged SQL statements return the list of captured messages that contain
* the SQL.
*/
public static List<String> stop() {
return basicAppender.collectEnd();
}
private static class BasicAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
List<String> messages = new ArrayList<String>();
@Override
protected void append(ILoggingEvent eventObject) {
if (started) {
messages.add(eventObject.getMessage());
}
}
/**
* Start collection.
*/
List<String> collectStart() {
List<String> tempMessages = messages;
messages = new ArrayList<String>();
// set started flag
start();
return tempMessages;
}
/**
* End collection.
*/
List<String> collectEnd() {
// set stopped state
stop();
List<String> tempMessages = messages;
messages = new ArrayList<String>();
return tempMessages;
}
}
}