mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Refactor internals of batch lazy loading and query fetches
This commit is contained in:
@@ -24,7 +24,7 @@ import java.io.Serializable;
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = Ebean.find(Order.class).join("details").findList();
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* </pre>
|
||||
@@ -51,8 +51,8 @@ import java.io.Serializable;
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new JoinConfig().query())
|
||||
* .fetch("customer", new JoinConfig().query(5))
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
@@ -70,7 +70,7 @@ import java.io.Serializable;
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().query(10))
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
@@ -96,13 +96,13 @@ import java.io.Serializable;
|
||||
* <pre class="code">
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(3).lazy(10))
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find customer where id in (?,?,?) // first 3 customers
|
||||
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 10 to load the customers
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
@@ -128,8 +128,8 @@ import java.io.Serializable;
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* find customer (name)
|
||||
* fetch contact (contactName, phone, email)
|
||||
* fetch shippingAddress (*)
|
||||
* fetch customer.contacts (contactName, phone, email)
|
||||
* fetch customer.shippingAddress (*)
|
||||
* where id in (?,?,?,?,?)
|
||||
*
|
||||
* </pre>
|
||||
@@ -159,6 +159,7 @@ public class FetchConfig implements Serializable {
|
||||
*/
|
||||
public FetchConfig lazy() {
|
||||
this.lazyBatchSize = 0;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -170,11 +171,12 @@ public class FetchConfig implements Serializable {
|
||||
*/
|
||||
public FetchConfig lazy(int lazyBatchSize) {
|
||||
this.lazyBatchSize = lazyBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be loaded as a separate query (rather than as
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* This will use the default batch size for separate query which is 100.
|
||||
@@ -187,14 +189,15 @@ public class FetchConfig implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be loaded as a separate query (rather than as
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* The queryBatchSize is the number of parent id's that this separate query
|
||||
* will load per batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This will load all beans on this path eagerly.
|
||||
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
|
||||
* is also used.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize
|
||||
@@ -202,12 +205,14 @@ public class FetchConfig implements Serializable {
|
||||
*/
|
||||
public FetchConfig query(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
this.queryAll = true;
|
||||
// queryAll true as long as a lazy batch size has not already been set
|
||||
this.queryAll = (lazyBatchSize == -1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #query(int)} but only fetches the first batch.
|
||||
* Eagerly fetch the first batch of beans on this path.
|
||||
* This is similar to {@link #query(int)} but only fetches the first batch.
|
||||
* <p>
|
||||
* If there are more parent beans than the batch size then they will not be
|
||||
* loaded eagerly but instead use lazy loading.
|
||||
@@ -228,7 +233,7 @@ public class FetchConfig implements Serializable {
|
||||
public int getLazyBatchSize() {
|
||||
return lazyBatchSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the batch size for separate query load.
|
||||
*/
|
||||
|
||||
@@ -32,6 +32,10 @@ public final class OrderBy<T> implements Serializable {
|
||||
public OrderBy() {
|
||||
this.list = new ArrayList<Property>(2);
|
||||
}
|
||||
|
||||
private OrderBy(List<Property> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orderBy parsing the order by clause.
|
||||
@@ -81,6 +85,17 @@ public final class OrderBy<T> implements Serializable {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this OrderBy with the path trimmed.
|
||||
*/
|
||||
public OrderBy<T> copyWithTrim(String path) {
|
||||
List<Property> newList = new ArrayList<Property>(list.size());
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
newList.add(list.get(i).copyWithTrim(path));
|
||||
}
|
||||
return new OrderBy<T>(newList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties for this OrderBy.
|
||||
*/
|
||||
@@ -196,6 +211,13 @@ public final class OrderBy<T> implements Serializable {
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this Property with the path trimmed.
|
||||
*/
|
||||
public Property copyWithTrim(String path) {
|
||||
return new Property(property.substring(path.length() + 1), ascending);
|
||||
}
|
||||
|
||||
protected int hash() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 31 + (ascending ? 0 : 1);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* A buffer of beans for batch lazy loading and secondary query loading.
|
||||
*/
|
||||
public interface LoadBeanBuffer {
|
||||
|
||||
public List<EntityBeanIntercept> getBatch();
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
public String getFullPath();
|
||||
|
||||
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty);
|
||||
|
||||
}
|
||||
@@ -1,39 +1,10 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* Controls the loading of ManyToOne and OneToOne relationships.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface LoadBeanContext extends LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Configure the query to load beans for this node/path.
|
||||
*/
|
||||
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty);
|
||||
|
||||
/**
|
||||
* Return the full path of this node from the root object.
|
||||
*/
|
||||
public String getFullPath();
|
||||
|
||||
/**
|
||||
* Return the persistence context used for all queries
|
||||
* related to this object graph.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for beans for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* Return the batchSize used for lazy loading beans.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
}
|
||||
|
||||
@@ -9,55 +9,52 @@ import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
* Request for loading ManyToOne and OneToOne relationships.
|
||||
*/
|
||||
public class LoadBeanRequest extends LoadRequest {
|
||||
|
||||
private final List<EntityBeanIntercept> batch;
|
||||
|
||||
private final LoadBeanContext loadContext;
|
||||
|
||||
private final String lazyLoadProperty;
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadBeanRequest(LoadBeanContext loadContext, List<EntityBeanIntercept> batch,
|
||||
Transaction transaction, int batchSize, boolean lazy, String lazyLoadProperty, boolean loadCache) {
|
||||
|
||||
super(transaction, batchSize, lazy);
|
||||
this.loadContext = loadContext;
|
||||
this.batch = batch;
|
||||
this.lazyLoadProperty = lazyLoadProperty;
|
||||
this.loadCache = loadCache;
|
||||
}
|
||||
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
private final List<EntityBeanIntercept> batch;
|
||||
|
||||
public String getDescription() {
|
||||
String fullPath = loadContext.getFullPath();
|
||||
String s = "path:" + fullPath + " batch:" + batchSize + " actual:"
|
||||
+ batch.size();
|
||||
return s;
|
||||
}
|
||||
private final LoadBeanBuffer LoadBuffer;
|
||||
|
||||
/**
|
||||
* Return the batch of beans to actually load.
|
||||
*/
|
||||
public List<EntityBeanIntercept> getBatch() {
|
||||
return batch;
|
||||
}
|
||||
private final String lazyLoadProperty;
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadBeanContext getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadBeanRequest(LoadBeanBuffer LoadBuffer, Transaction transaction, boolean lazy, String lazyLoadProperty,
|
||||
boolean loadCache) {
|
||||
|
||||
super(transaction, lazy);
|
||||
this.LoadBuffer = LoadBuffer;
|
||||
this.batch = LoadBuffer.getBatch();
|
||||
this.lazyLoadProperty = lazyLoadProperty;
|
||||
this.loadCache = loadCache;
|
||||
}
|
||||
|
||||
public boolean isLoadCache() {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "path:" + LoadBuffer.getFullPath() + " batch:" + batch.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch of beans to actually load.
|
||||
*/
|
||||
public List<EntityBeanIntercept> getBatch() {
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadBeanBuffer getLoadContext() {
|
||||
return LoadBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property that invoked the lazy loading.
|
||||
*/
|
||||
public String getLazyLoadProperty() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property that invoked the lazy loading.
|
||||
*/
|
||||
public String getLazyLoadProperty() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
|
||||
/**
|
||||
* A buffer of bean collections for batch lazy loading and secondary query loading.
|
||||
*/
|
||||
public interface LoadManyBuffer {
|
||||
|
||||
public List<BeanCollection<?>> getBatch();
|
||||
|
||||
public BeanPropertyAssocMany<?> getBeanProperty();
|
||||
|
||||
public ObjectGraphNode getObjectGraphNode();
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
public String getFullPath();
|
||||
|
||||
public void configureQuery(SpiQuery<?> query);
|
||||
|
||||
}
|
||||
@@ -1,54 +1,9 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
|
||||
/**
|
||||
* Controls the loading of OneToMany and ManyToMany relationships.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface LoadManyContext extends LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Configure the query to load beans for this node/path.
|
||||
*/
|
||||
public void configureQuery(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the full path of this node from the root object.
|
||||
*/
|
||||
public String getFullPath();
|
||||
|
||||
/**
|
||||
* Return the node location for this node/path.
|
||||
*/
|
||||
public ObjectGraphNode getObjectGraphNode();
|
||||
|
||||
|
||||
/**
|
||||
* Return the persistence context used for all queries
|
||||
* related to this object graph.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the batchSize used for lazy loading beans.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for beans for this node.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* Return the associated Many bean property.
|
||||
*/
|
||||
public BeanPropertyAssocMany<?> getBeanProperty();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,28 +13,24 @@ public class LoadManyRequest extends LoadRequest {
|
||||
|
||||
private final List<BeanCollection<?>> batch;
|
||||
|
||||
private final LoadManyContext loadContext;
|
||||
private final LoadManyBuffer loadContext;
|
||||
|
||||
private final boolean onlyIds;
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadManyRequest(LoadManyContext loadContext,
|
||||
List<BeanCollection<?>> batch, Transaction transaction,
|
||||
int batchSize, boolean lazy, boolean onlyIds, boolean loadCache) {
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, Transaction transaction, int batchSize, boolean lazy,
|
||||
boolean onlyIds, boolean loadCache) {
|
||||
|
||||
super(transaction, batchSize, lazy);
|
||||
super(transaction, lazy);
|
||||
this.loadContext = loadContext;
|
||||
this.batch = batch;
|
||||
this.batch = loadContext.getBatch();
|
||||
this.onlyIds = onlyIds;
|
||||
this.loadCache = loadCache;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
String fullPath = loadContext.getFullPath();
|
||||
String s = "path:" + fullPath + " batch:" + batchSize + " actual:"
|
||||
+ batch.size();
|
||||
return s;
|
||||
return "path:" + loadContext.getFullPath() + " size:"+ batch.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +43,7 @@ public class LoadManyRequest extends LoadRequest {
|
||||
/**
|
||||
* Return the load context.
|
||||
*/
|
||||
public LoadManyContext getLoadContext() {
|
||||
public LoadManyBuffer getLoadContext() {
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,18 +9,14 @@ public abstract class LoadRequest {
|
||||
|
||||
protected final boolean lazy;
|
||||
|
||||
protected final int batchSize;
|
||||
|
||||
protected final Transaction transaction;
|
||||
|
||||
public LoadRequest(Transaction transaction, int batchSize, boolean lazy) {
|
||||
public LoadRequest(Transaction transaction, boolean lazy) {
|
||||
|
||||
this.transaction = transaction;
|
||||
this.batchSize = batchSize;
|
||||
this.lazy = lazy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if this is a lazy load and false if it is a secondary query.
|
||||
*/
|
||||
@@ -28,13 +24,6 @@ public abstract class LoadRequest {
|
||||
return lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the requested batch size.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction to use if this is a secondary query.
|
||||
* <p>
|
||||
|
||||
@@ -18,10 +18,10 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
|
||||
*/
|
||||
public List<SpiExpression> getUnderlyingList();
|
||||
|
||||
/**
|
||||
* Trim the path for filterMany() expressions.
|
||||
*/
|
||||
public void trimPath(int prefixTrim);
|
||||
/**
|
||||
* Return a copy of the ExpressionList with the path trimmed for filterMany() expressions.
|
||||
*/
|
||||
public SpiExpressionList<?> trimPath(int prefixTrim);
|
||||
|
||||
/**
|
||||
* Restore the ExpressionFactory after deserialisation.
|
||||
|
||||
@@ -15,10 +15,10 @@ import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanBuffer;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyContext;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyBuffer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
@@ -27,8 +27,6 @@ import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
/**
|
||||
* Helper to handle lazy loading and refreshing of beans.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DefaultBeanLoader {
|
||||
|
||||
@@ -50,32 +48,29 @@ public class DefaultBeanLoader {
|
||||
* re-use the query plan cache and get DB statement re-use.
|
||||
* </p>
|
||||
*/
|
||||
private int getBatchSize(int batchListSize, int requestedBatchSize) {
|
||||
if (batchListSize == requestedBatchSize) {
|
||||
return batchListSize;
|
||||
}
|
||||
if (batchListSize == 1) {
|
||||
private int getBatchSize(int batchSize) {
|
||||
|
||||
if (batchSize == 1) {
|
||||
// there is only one bean/collection to load
|
||||
return 1;
|
||||
}
|
||||
if (requestedBatchSize <= 5) {
|
||||
if (batchSize <= 5) {
|
||||
// anything less than 5 becomes 5
|
||||
return 5;
|
||||
}
|
||||
if (batchListSize <= 10 || requestedBatchSize <= 10) {
|
||||
// 10 or less to load
|
||||
// ... or we wanted a batch size between 6 and 10
|
||||
if (batchSize <= 10) {
|
||||
return 10;
|
||||
}
|
||||
if (batchListSize <= 20 || requestedBatchSize <= 20) {
|
||||
// 20 or less to load
|
||||
// ... or we wanted a batch size between 11 and 20
|
||||
if (batchSize <= 20) {
|
||||
return 20;
|
||||
}
|
||||
if (batchListSize <= 50) {
|
||||
if (batchSize <= 50) {
|
||||
return 50;
|
||||
}
|
||||
return requestedBatchSize;
|
||||
if (batchSize <= 100) {
|
||||
return 100;
|
||||
}
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public void refreshMany(Object parentBean, String propertyName) {
|
||||
@@ -86,9 +81,9 @@ public class DefaultBeanLoader {
|
||||
|
||||
List<BeanCollection<?>> batch = loadRequest.getBatch();
|
||||
|
||||
int batchSize = getBatchSize(batch.size(), loadRequest.getBatchSize());
|
||||
int batchSize = getBatchSize(batch.size());
|
||||
|
||||
LoadManyContext ctx = loadRequest.getLoadContext();
|
||||
LoadManyBuffer ctx = loadRequest.getLoadContext();
|
||||
BeanPropertyAssocMany<?> many = ctx.getBeanProperty();
|
||||
|
||||
PersistenceContext pc = ctx.getPersistenceContext();
|
||||
@@ -154,14 +149,14 @@ public class DefaultBeanLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, LoadManyContext ctx, boolean onlyIds) {
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
Object parentBean = bc.getOwnerBean();
|
||||
String propertyName = bc.getPropertyName();
|
||||
|
||||
ObjectGraphNode node = ctx == null ? null : ctx.getObjectGraphNode();
|
||||
//ObjectGraphNode node = ctx == null ? null : ctx.getObjectGraphNode();
|
||||
|
||||
loadManyInternal(parentBean, propertyName, null, false, node, onlyIds);
|
||||
loadManyInternal(parentBean, propertyName, null, false, null, onlyIds);
|
||||
}
|
||||
|
||||
public void refreshMany(Object parentBean, String propertyName, Transaction t) {
|
||||
@@ -170,17 +165,15 @@ public class DefaultBeanLoader {
|
||||
|
||||
private void loadManyInternal(Object parentBean, String propertyName, Transaction t, boolean refresh, ObjectGraphNode node, boolean onlyIds) {
|
||||
|
||||
EntityBeanIntercept ebi = null;
|
||||
PersistenceContext pc = null;
|
||||
BeanCollection<?> beanCollection = null;
|
||||
ExpressionList<?> filterMany = null;
|
||||
|
||||
ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
pc = ebi.getPersistenceContext();
|
||||
EntityBeanIntercept ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>) parentDesc.getBeanProperty(propertyName);
|
||||
|
||||
BeanCollection<?> beanCollection = null;
|
||||
ExpressionList<?> filterMany = null;
|
||||
|
||||
Object currentValue = many.getValue(parentBean);
|
||||
if (currentValue instanceof BeanCollection<?>) {
|
||||
beanCollection = (BeanCollection<?>) currentValue;
|
||||
@@ -270,9 +263,9 @@ public class DefaultBeanLoader {
|
||||
throw new RuntimeException("Nothing in batch?");
|
||||
}
|
||||
|
||||
int batchSize = getBatchSize(batch.size(), loadRequest.getBatchSize());
|
||||
int batchSize = getBatchSize(batch.size());
|
||||
|
||||
LoadBeanContext ctx = loadRequest.getLoadContext();
|
||||
LoadBeanBuffer ctx = loadRequest.getLoadContext();
|
||||
BeanDescriptor<?> desc = ctx.getBeanDescriptor();
|
||||
|
||||
Class<?> beanType = desc.getBeanType();
|
||||
@@ -349,7 +342,6 @@ public class DefaultBeanLoader {
|
||||
ebis[i].setLazyLoadFailure();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void refresh(Object bean) {
|
||||
@@ -362,7 +354,6 @@ public class DefaultBeanLoader {
|
||||
|
||||
private void refreshBeanInternal(Object bean, SpiQuery.Mode mode) {
|
||||
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) bean)._ebean_getIntercept();;
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
private final CQueryEngine cqueryEngine;
|
||||
|
||||
@Deprecated
|
||||
//@Deprecated
|
||||
private DdlGenerator ddlGenerator;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
@@ -188,14 +188,16 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
*/
|
||||
private int lazyLoadBatchSize;
|
||||
|
||||
/** The query batch size */
|
||||
/**
|
||||
* The query batch size
|
||||
*/
|
||||
private int queryBatchSize;
|
||||
|
||||
/**
|
||||
* JDBC driver specific handling for JDBC batch execution.
|
||||
*/
|
||||
private PstmtBatch pstmtBatch;
|
||||
|
||||
|
||||
/**
|
||||
* holds plugins (e.g. ddl generator) detected by the service loader
|
||||
*/
|
||||
@@ -502,7 +504,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
beanLoader.loadMany(bc, null, onlyIds);
|
||||
beanLoader.loadMany(bc, onlyIds);
|
||||
}
|
||||
|
||||
public void refresh(Object bean) {
|
||||
|
||||
@@ -5,38 +5,36 @@ import java.io.Serializable;
|
||||
/**
|
||||
* This is the path prefix for filterMany.
|
||||
* <p>
|
||||
* The actual path can change due to FetchConfig query joins that proceed
|
||||
* the query that includes the filterMany.
|
||||
* The actual path can change due to FetchConfig query joins that proceed the
|
||||
* query that includes the filterMany.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class FilterExprPath implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6420905565372842018L;
|
||||
|
||||
/**
|
||||
* The path of the filterMany.
|
||||
*/
|
||||
private String path;
|
||||
|
||||
public FilterExprPath(String path){
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim off leading part of the path due to a
|
||||
* proceeding (earlier) query join etc.
|
||||
*/
|
||||
public void trimPath(int prefixTrim) {
|
||||
path = path.substring(prefixTrim);
|
||||
}
|
||||
private static final long serialVersionUID = -6420905565372842018L;
|
||||
|
||||
/**
|
||||
* Return the path. This is a prefix used in the filterMany expressions.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
/**
|
||||
* The path of the filterMany.
|
||||
*/
|
||||
private String path;
|
||||
|
||||
public FilterExprPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the FilterExprPath trimming off leading part of the path
|
||||
* due to a proceeding (earlier) query join etc.
|
||||
*/
|
||||
public FilterExprPath trimPath(int prefixTrim) {
|
||||
return new FilterExprPath(path.substring(prefixTrim));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path. This is a prefix used in the filterMany expressions.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
|
||||
import com.avaje.ebean.FetchConfig;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
/**
|
||||
* Base class for Bean and BeanCollection loading (lazy loading and query join loading).
|
||||
*/
|
||||
public abstract class DLoadBaseContext {
|
||||
|
||||
protected final DLoadContext parent;
|
||||
|
||||
protected final BeanDescriptor<?> desc;
|
||||
|
||||
protected final String path;
|
||||
|
||||
protected final String fullPath;
|
||||
|
||||
protected final OrmQueryProperties queryProps;
|
||||
|
||||
protected final boolean hitCache;
|
||||
|
||||
protected final String serverName;
|
||||
|
||||
protected final int firstBatchSize;
|
||||
|
||||
protected final int secondaryBatchSize;
|
||||
|
||||
protected final ObjectGraphNode objectGraphNode;
|
||||
|
||||
protected final boolean queryFetch;
|
||||
|
||||
|
||||
public DLoadBaseContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
this.parent = parent;
|
||||
this.serverName = parent.getEbeanServer().getName();
|
||||
this.desc = desc;
|
||||
this.queryProps = queryProps;
|
||||
this.path = path;
|
||||
this.fullPath = parent.getFullPath(path);
|
||||
|
||||
this.hitCache = !parent.isExcludeBeanCache() && desc.isBeanCaching();
|
||||
|
||||
this.objectGraphNode = parent.getObjectGraphNode(path);
|
||||
|
||||
this.queryFetch = queryProps != null && queryProps.isQueryFetch();
|
||||
this.firstBatchSize = initFirstBatchSize(defaultBatchSize, queryProps);
|
||||
this.secondaryBatchSize = initSecondaryBatchSize(defaultBatchSize, firstBatchSize, queryProps);
|
||||
}
|
||||
|
||||
private int initFirstBatchSize(int batchSize, OrmQueryProperties queryProps) {
|
||||
if (queryProps == null) {
|
||||
return batchSize;
|
||||
}
|
||||
FetchConfig fetchConfig = queryProps.getFetchConfig();
|
||||
if (fetchConfig == null) {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
int queryBatchSize = fetchConfig.getQueryBatchSize();
|
||||
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 {
|
||||
return queryBatchSize;
|
||||
}
|
||||
}
|
||||
|
||||
private int initSecondaryBatchSize(int defaultBatchSize, int firstBatchSize, OrmQueryProperties queryProps) {
|
||||
if (queryProps == null) {
|
||||
return defaultBatchSize;
|
||||
}
|
||||
FetchConfig fetchConfig = queryProps.getFetchConfig();
|
||||
if (fetchConfig == null) {
|
||||
return defaultBatchSize;
|
||||
}
|
||||
if (fetchConfig.isQueryAll()) {
|
||||
return firstBatchSize;
|
||||
}
|
||||
|
||||
int lazyBatchSize = fetchConfig.getLazyBatchSize();
|
||||
return (lazyBatchSize > 1) ? lazyBatchSize : defaultBatchSize;
|
||||
}
|
||||
|
||||
protected PersistenceContext getPersistenceContext() {
|
||||
return parent.getPersistenceContext();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +1,44 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.BeanLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanBuffer;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Default implementation of LoadBeanContext.
|
||||
*
|
||||
*/
|
||||
public class DLoadBeanContext implements LoadBeanContext, BeanLoader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DLoadBeanContext.class);
|
||||
public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext{
|
||||
|
||||
protected final DLoadContext parent;
|
||||
private List<LoadBuffer> bufferList;
|
||||
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
protected final BeanDescriptor<?> desc;
|
||||
|
||||
protected final String path;
|
||||
|
||||
protected final String fullPath;
|
||||
|
||||
private final DLoadList<EntityBeanIntercept> weakList;
|
||||
|
||||
private final OrmQueryProperties queryProps;
|
||||
|
||||
private int batchSize;
|
||||
|
||||
public DLoadBeanContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int batchSize,
|
||||
OrmQueryProperties queryProps, DLoadList<EntityBeanIntercept> weakList) {
|
||||
public DLoadBeanContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
this.parent = parent;
|
||||
this.desc = desc;
|
||||
this.path = path;
|
||||
this.batchSize = batchSize;
|
||||
this.queryProps = queryProps;
|
||||
this.weakList = weakList;
|
||||
|
||||
if (parent.getRelativePath() == null) {
|
||||
this.fullPath = path;
|
||||
} else {
|
||||
this.fullPath = parent.getRelativePath() + "." + path;
|
||||
}
|
||||
super(parent, desc, path, defaultBatchSize, queryProps);
|
||||
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
this.bufferList = queryFetch ? new ArrayList<DLoadBeanContext.LoadBuffer>() : null;
|
||||
}
|
||||
|
||||
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
|
||||
|
||||
protected void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
|
||||
|
||||
// propagate the readOnly state
|
||||
if (parent.isReadOnly() != null) {
|
||||
query.setReadOnly(parent.isReadOnly());
|
||||
}
|
||||
query.setParentNode(getObjectGraphNode());
|
||||
query.setParentNode(objectGraphNode);
|
||||
query.setLazyLoadProperty(lazyLoadProperty);
|
||||
|
||||
if (queryProps != null) {
|
||||
@@ -74,181 +49,131 @@ public class DLoadBeanContext implements LoadBeanContext, BeanLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public String getFullPath() {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return parent.getPersistenceContext();
|
||||
}
|
||||
protected void register(EntityBeanIntercept ebi){
|
||||
|
||||
public OrmQueryProperties getQueryProps() {
|
||||
return queryProps;
|
||||
}
|
||||
|
||||
public ObjectGraphNode getObjectGraphNode() {
|
||||
return parent.getObjectGraphNode(path);
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return parent.getEbeanServer().getName();
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public void setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public LoadContext getGraphContext() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void register(EntityBeanIntercept ebi){
|
||||
int pos = weakList.add(ebi);
|
||||
ebi.setBeanLoader(pos, this, parent.getPersistenceContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we can load the bean from L2 cache. If so avoid loading from the DB.
|
||||
*/
|
||||
private boolean loadBeanFromCache(EntityBeanIntercept ebi, int position) {
|
||||
|
||||
if (!desc.loadFromCache(ebi)) {
|
||||
return false;
|
||||
}
|
||||
// we loaded the bean from cache
|
||||
weakList.removeEntry(position);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Loading path:" + fullPath + " - bean loaded from L2 cache, position[" + position + "]");
|
||||
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext());
|
||||
if (currentBuffer.add(ebi)) {
|
||||
// the currentBuffer is full so create another one
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load this bean and potentially a batch of similar beans.
|
||||
*/
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
|
||||
// A synchronized (this) is effectively held by EntityBeanIntercept.loadBean()
|
||||
|
||||
if (desc.lazyLoadMany(ebi)) {
|
||||
// lazy load property was a Many
|
||||
return;
|
||||
}
|
||||
|
||||
int position = ebi.getBeanLoaderIndex();
|
||||
boolean hitCache = !parent.isExcludeBeanCache() && desc.isBeanCaching();
|
||||
|
||||
if (hitCache && loadBeanFromCache(ebi, position)) {
|
||||
// successfully hit the L2 cache so don't invoke DB lazy loading
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a batch of beans to lazy load
|
||||
List<EntityBeanIntercept> batch = null;
|
||||
try {
|
||||
batch = weakList.getLoadBatch(position, batchSize);
|
||||
} catch (IllegalStateException e) {
|
||||
logger.error("type[" + desc.getFullName() + "] fullPath[" + fullPath + "] batchSize[" + batchSize + "]", e);
|
||||
}
|
||||
|
||||
if (hitCache && batchSize > 1) {
|
||||
// Check each of the beans in the batch to see if they are in the L2 cache.
|
||||
// Add more as necessary to make up our batch that will be loaded.
|
||||
batch = loadBeanCheckBatch(batch);
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
for (int i = 0; i < batch.size(); i++) {
|
||||
|
||||
EntityBeanIntercept entityBeanIntercept = batch.get(i);
|
||||
EntityBean owner = entityBeanIntercept.getOwner();
|
||||
Object id = desc.getId(owner);
|
||||
|
||||
logger.trace("LoadBean type["+owner.getClass().getName()+"] fullPath["+fullPath+"] id["+id+"] batchIndex["+i+"] beanLoaderIndex["+entityBeanIntercept.getBeanLoaderIndex()+"]");
|
||||
}
|
||||
}
|
||||
|
||||
LoadBeanRequest req = new LoadBeanRequest(this, batch, null, batchSize, true, ebi.getLazyLoadProperty(), hitCache);
|
||||
parent.getEbeanServer().loadBean(req);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check each of the beans in the batch to see if they are in the cache.
|
||||
* Get more beans out as necessary to get our desired batch size.
|
||||
*/
|
||||
private List<EntityBeanIntercept> loadBeanCheckBatch(List<EntityBeanIntercept> batch) {
|
||||
|
||||
|
||||
List<EntityBeanIntercept> actualLoadBatch = new ArrayList<EntityBeanIntercept>(batchSize);
|
||||
List<EntityBeanIntercept> batchToCheck = batch;
|
||||
|
||||
int loadedFromCache = 0;
|
||||
|
||||
while (true) {
|
||||
// check each bean (not already checked) to see if it is in the cache
|
||||
for (int i = 0; i < batchToCheck.size(); i++) {
|
||||
if (!desc.loadFromCache(batchToCheck.get(i))) {
|
||||
actualLoadBatch.add(batchToCheck.get(i));
|
||||
} else {
|
||||
loadedFromCache++;
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace( "Loading path:" + fullPath + " - bean loaded from L2 cache(batch)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (batchToCheck.isEmpty()) {
|
||||
// we have exhausted all the beans that need lazy loading
|
||||
break;
|
||||
}
|
||||
int more = batchSize - actualLoadBatch.size();
|
||||
if (more <= 0 || loadedFromCache > 500) {
|
||||
break;
|
||||
}
|
||||
// get some more to check as we loaded some from L2 cache
|
||||
batchToCheck = weakList.getNextBatch(more);
|
||||
}
|
||||
return actualLoadBatch;
|
||||
}
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
LoadBuffer buffer = new LoadBuffer(this, size);
|
||||
if (bufferList != null) {
|
||||
bufferList.add(buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all) {
|
||||
|
||||
if (!queryFetch) {
|
||||
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
|
||||
}
|
||||
synchronized (this) {
|
||||
do {
|
||||
List<EntityBeanIntercept> batch = weakList.getNextBatch(requestedBatchSize);
|
||||
if (batch.size() == 0) {
|
||||
// there are no beans to load
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Loading path:" + fullPath + " - no more beans to load");
|
||||
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
boolean loadCache = false;
|
||||
LoadBeanRequest req = new LoadBeanRequest(loadBuffer, parentRequest.getTransaction(), false, null, loadCache);
|
||||
|
||||
parent.getEbeanServer().loadBean(req);
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
// this is only run once - secondary query is a one shot deal
|
||||
this.bufferList = null;
|
||||
}
|
||||
boolean loadCache = false;
|
||||
LoadBeanRequest req = new LoadBeanRequest(this, batch, parentRequest.getTransaction(), requestedBatchSize, false, null, loadCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Loading path:" + fullPath + " - secondary query batch load [" + batch.size() + "] beans");
|
||||
/**
|
||||
* A buffer for batch loading beans on a given path.
|
||||
*/
|
||||
public static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
|
||||
|
||||
private final DLoadBeanContext context;
|
||||
private final int batchSize;
|
||||
private final List<EntityBeanIntercept> list;
|
||||
|
||||
public LoadBuffer(DLoadBeanContext context, int batchSize) {
|
||||
this.context = context;
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<EntityBeanIntercept>(batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean add(EntityBeanIntercept ebi) {
|
||||
list.add(ebi);
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntityBeanIntercept> getBatch() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return context.serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return context.desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return context.getPersistenceContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
|
||||
context.configureQuery(query, lazyLoadProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
// A synchronized (this) is effectively held by EntityBeanIntercept.loadBean()
|
||||
|
||||
if (context.desc.lazyLoadMany(ebi)) {
|
||||
// lazy load property was a Many
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.hitCache && context.desc.loadFromCache(ebi)) {
|
||||
// successfully hit the L2 cache so don't invoke DB lazy loading
|
||||
list.remove(ebi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.hitCache) {
|
||||
// Check each of the beans in the batch to see if they are in the L2 cache.
|
||||
Iterator<EntityBeanIntercept> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
EntityBeanIntercept bean = iterator.next();
|
||||
if (context.desc.loadFromCache(bean)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent.getEbeanServer().loadBean(req);
|
||||
if (!all) {
|
||||
break;
|
||||
}
|
||||
LoadBeanRequest req = new LoadBeanRequest(this, null, true, ebi.getLazyLoadProperty(), context.hitCache);
|
||||
context.desc.getEbeanServer().loadBean(req);
|
||||
}
|
||||
|
||||
} while (true);
|
||||
@Override
|
||||
public String getFullPath() {
|
||||
return context.fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.ObjectGraphOrigin;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
import com.avaje.ebeaninternal.api.LoadSecondaryQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -24,8 +23,6 @@ import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
/**
|
||||
* Default implementation of LoadContext.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DLoadContext implements LoadContext {
|
||||
|
||||
@@ -48,7 +45,6 @@ public class DLoadContext implements LoadContext {
|
||||
private final String relativePath;
|
||||
private final ObjectGraphOrigin origin;
|
||||
private final boolean useAutofetchManager;
|
||||
private final boolean hardRefs;
|
||||
|
||||
private final Map<String,ObjectGraphNode> nodePathMap = new HashMap<String, ObjectGraphNode>();
|
||||
|
||||
@@ -66,10 +62,9 @@ public class DLoadContext implements LoadContext {
|
||||
boolean excludeBeanCache, ObjectGraphNode parentNode, boolean useAutofetchManager) {
|
||||
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.hardRefs = GlobalProperties.getBoolean("ebean.hardrefs", false);
|
||||
this.defaultBatchSize = ebeanServer.getLazyLoadBatchSize();
|
||||
this.rootDescriptor = rootDescriptor;
|
||||
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null, createBeanLoadList());
|
||||
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null);
|
||||
this.readOnly = readOnly;
|
||||
this.excludeBeanCache = excludeBeanCache;
|
||||
this.useAutofetchManager = useAutofetchManager;
|
||||
@@ -210,6 +205,14 @@ public class DLoadContext implements LoadContext {
|
||||
public String getRelativePath() {
|
||||
return relativePath;
|
||||
}
|
||||
|
||||
protected String getFullPath(String path) {
|
||||
if (relativePath == null) {
|
||||
return path;
|
||||
} else {
|
||||
return relativePath + "." + path;
|
||||
}
|
||||
}
|
||||
|
||||
protected SpiEbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
@@ -282,24 +285,7 @@ public class DLoadContext implements LoadContext {
|
||||
|
||||
BeanPropertyAssocMany<?> p = (BeanPropertyAssocMany<?>)getBeanProperty(rootDescriptor, path);
|
||||
|
||||
return new DLoadManyContext(this, p, path, batchSize, queryProps, createBeanCollectionLoadList());
|
||||
}
|
||||
|
||||
|
||||
private DLoadList<EntityBeanIntercept> createBeanLoadList() {
|
||||
if (hardRefs){
|
||||
return new DLoadHardList<EntityBeanIntercept>();
|
||||
} else {
|
||||
return new DLoadWeakList<EntityBeanIntercept>();
|
||||
}
|
||||
}
|
||||
|
||||
private DLoadList<BeanCollection<?>> createBeanCollectionLoadList() {
|
||||
if (hardRefs){
|
||||
return new DLoadHardList<BeanCollection<?>>();
|
||||
} else {
|
||||
return new DLoadWeakList<BeanCollection<?>>();
|
||||
}
|
||||
return new DLoadManyContext(this, p, path, batchSize, queryProps);
|
||||
}
|
||||
|
||||
private DLoadBeanContext createBeanContext(String path, int batchSize, OrmQueryProperties queryProps) {
|
||||
@@ -307,11 +293,10 @@ public class DLoadContext implements LoadContext {
|
||||
BeanPropertyAssoc<?> p = (BeanPropertyAssoc<?>)getBeanProperty(rootDescriptor, path);
|
||||
BeanDescriptor<?> targetDescriptor = p.getTargetDescriptor();
|
||||
|
||||
return new DLoadBeanContext(this, targetDescriptor, path, batchSize, queryProps, createBeanLoadList());
|
||||
return new DLoadBeanContext(this, targetDescriptor, path, batchSize, queryProps);
|
||||
}
|
||||
|
||||
private BeanProperty getBeanProperty(BeanDescriptor<?> desc, String path){
|
||||
|
||||
return desc.getBeanPropertyFromPath(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DLoadHardList<T> implements DLoadList<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DLoadHardList.class);
|
||||
|
||||
protected final ArrayList<T> list = new ArrayList<T>();
|
||||
|
||||
protected int removedFromTop;
|
||||
|
||||
protected DLoadHardList() {
|
||||
|
||||
}
|
||||
|
||||
public int add(T e) {
|
||||
synchronized (this) {
|
||||
int i = list.size();
|
||||
list.add(e);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEntry(int position) {
|
||||
synchronized (this) {
|
||||
T object = list.get(position);
|
||||
if (object == null) {
|
||||
logger.warn("removeEntry found no Object for position[" + position + "]");
|
||||
} else {
|
||||
// just set the entry to null
|
||||
list.set(position, null);
|
||||
}
|
||||
if (position == removedFromTop) {
|
||||
removedFromTop++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<T> getNextBatch(int batchSize) {
|
||||
if (removedFromTop >= list.size()){
|
||||
return new ArrayList<T>(0);
|
||||
}
|
||||
return getLoadBatch(removedFromTop, batchSize, true);
|
||||
}
|
||||
|
||||
public List<T> getLoadBatch(int position, int batchSize) {
|
||||
return getLoadBatch(position, batchSize, false);
|
||||
}
|
||||
|
||||
private List<T> getLoadBatch(int position, int batchSize, boolean ignoreMissing) {
|
||||
|
||||
synchronized (this) {
|
||||
if (batchSize < 1) {
|
||||
throw new RuntimeException("batchSize " + batchSize + " < 1 ??!!");
|
||||
}
|
||||
|
||||
ArrayList<T> batch = new ArrayList<T>();
|
||||
|
||||
if (!addObjectToBatchAt(batch, position) && !ignoreMissing) {
|
||||
String msg = "getLoadBatch position[" + position + "] didn't find a bean in the list?";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
||||
for (int i = position; i < list.size(); i++) {
|
||||
addObjectToBatchAt(batch, i);
|
||||
if (batch.size() == batchSize) {
|
||||
// found enough beans going forward
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
|
||||
// search the front of the list to fill our batch
|
||||
for (int i = removedFromTop; i < position; i++) {
|
||||
addObjectToBatchAt(batch, i);
|
||||
if (batch.size() == batchSize) {
|
||||
// found enough beans going forward from start of list
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addObjectToBatchAt(ArrayList<T> batch, int i) {
|
||||
|
||||
boolean found = false;
|
||||
T object = list.get(i);
|
||||
if (object != null) {
|
||||
found = true;
|
||||
batch.add(object);
|
||||
// set it to null saying we have loaded this one
|
||||
list.set(i, null);
|
||||
}
|
||||
|
||||
if (i == removedFromTop) {
|
||||
removedFromTop++;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
@@ -8,55 +9,45 @@ import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.LoadManyContext;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyBuffer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
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.querydefn.OrmQueryProperties;
|
||||
|
||||
public class DLoadManyContext implements LoadManyContext, BeanCollectionLoader {
|
||||
|
||||
protected final DLoadContext parent;
|
||||
|
||||
protected final String fullPath;
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
public class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
|
||||
private final BeanPropertyAssocMany<?> property;
|
||||
|
||||
private final String path;
|
||||
protected final BeanPropertyAssocMany<?> property;
|
||||
|
||||
private List<LoadBuffer> bufferList;
|
||||
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property,
|
||||
String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
private final int batchSize;
|
||||
|
||||
private final OrmQueryProperties queryProps;
|
||||
|
||||
private final DLoadList<BeanCollection<?>> weakList;
|
||||
|
||||
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> p,
|
||||
String path, int batchSize, OrmQueryProperties queryProps, DLoadList<BeanCollection<?>> weakList) {
|
||||
|
||||
this.parent = parent;
|
||||
this.property = p;
|
||||
this.desc = p.getBeanDescriptor();
|
||||
this.path = path;
|
||||
this.batchSize = batchSize;
|
||||
this.queryProps = queryProps;
|
||||
this.weakList = weakList;//new DLoadWeakList<BeanCollection<?>>();
|
||||
|
||||
if (parent.getRelativePath() == null){
|
||||
this.fullPath = path;
|
||||
} else {
|
||||
this.fullPath = parent.getRelativePath()+"."+path;
|
||||
}
|
||||
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
|
||||
|
||||
this.property = property;
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
this.bufferList = queryFetch ? new ArrayList<DLoadManyContext.LoadBuffer>() : null;
|
||||
}
|
||||
|
||||
public void configureQuery(SpiQuery<?> query){
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
LoadBuffer buffer = new LoadBuffer(this, size);
|
||||
if (bufferList != null) {
|
||||
bufferList.add(buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void configureQuery(SpiQuery<?> query){
|
||||
|
||||
// propagate the readOnly state
|
||||
if (parent.isReadOnly() != null){
|
||||
query.setReadOnly(parent.isReadOnly());
|
||||
}
|
||||
if (parent.isReadOnly() != null){
|
||||
query.setReadOnly(parent.isReadOnly());
|
||||
}
|
||||
query.setParentNode(getObjectGraphNode());
|
||||
|
||||
if (queryProps != null){
|
||||
@@ -82,18 +73,6 @@ public class DLoadManyContext implements LoadManyContext, BeanCollectionLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public String getFullPath() {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return parent.getPersistenceContext();
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?> getBeanProperty() {
|
||||
return property;
|
||||
}
|
||||
@@ -102,60 +81,130 @@ public class DLoadManyContext implements LoadManyContext, BeanCollectionLoader {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return parent.getEbeanServer().getName();
|
||||
}
|
||||
|
||||
public void register(BeanCollection<?> bc){
|
||||
int pos = weakList.add(bc);
|
||||
bc.setLoader(pos, this);
|
||||
|
||||
bc.setLoader(0, currentBuffer);
|
||||
if (currentBuffer.add(bc)) {
|
||||
// the currentBuffer is full so create another one
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
int position = bc.getLoaderIndex();
|
||||
|
||||
LoadManyRequest req;
|
||||
synchronized (weakList) {
|
||||
boolean hitCache = desc.isBeanCaching() && !onlyIds && !parent.isExcludeBeanCache();
|
||||
if (hitCache){
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
BeanDescriptor<? extends Object> parentDesc = desc.getBeanDescriptor(ownerBean.getClass());
|
||||
Object parentId = parentDesc.getId(ownerBean);
|
||||
if (parentDesc.cacheLoadMany(property, bc, parentId, parent.isReadOnly())) {
|
||||
// we loaded the bean from cache
|
||||
weakList.removeEntry(position);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<BeanCollection<?>> loadBatch = weakList.getLoadBatch(position, batchSize);
|
||||
req = new LoadManyRequest(this, loadBatch, null, batchSize, true, onlyIds, hitCache);
|
||||
}
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
}
|
||||
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all){
|
||||
|
||||
do {
|
||||
LoadManyRequest req;
|
||||
synchronized (weakList) {
|
||||
List<BeanCollection<?>> batch = weakList.getNextBatch(requestedBatchSize);
|
||||
if (batch.size() == 0){
|
||||
return;
|
||||
}
|
||||
req = new LoadManyRequest(this, batch, parentRequest.getTransaction(), requestedBatchSize, false, false, false);
|
||||
}
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
if (!all){
|
||||
// queryFirst(batch)
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
if (!queryFetch) {
|
||||
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
|
||||
}
|
||||
synchronized (this) {
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest.getTransaction(), requestedBatchSize, false, false, false);
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is only run once - secondary query is a one shot deal
|
||||
this.bufferList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A buffer for batch loading bean collections on a given path.
|
||||
* Supports batch lazy loading and secondary query loading.
|
||||
*/
|
||||
public static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
|
||||
|
||||
private final DLoadManyContext context;
|
||||
private final int batchSize;
|
||||
private final List<BeanCollection<?>> list;
|
||||
|
||||
public LoadBuffer(DLoadManyContext context, int batchSize) {
|
||||
this.context = context;
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<BeanCollection<?>>(batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean add(BeanCollection<?> bc) {
|
||||
list.add(bc);
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BeanCollection<?>> getBatch() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanPropertyAssocMany<?> getBeanProperty() {
|
||||
return context.property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getObjectGraphNode() {
|
||||
return context.getObjectGraphNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureQuery(SpiQuery<?> query){
|
||||
context.configureQuery(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return context.serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return context.desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return context.getPersistenceContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullPath() {
|
||||
return context.fullPath;
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
synchronized (this) {
|
||||
boolean useCache = context.hitCache && !onlyIds;
|
||||
if (useCache) {
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
BeanDescriptor<? extends Object> parentDesc = context.desc.getBeanDescriptor(ownerBean.getClass());
|
||||
Object parentId = parentDesc.getId(ownerBean);
|
||||
if (parentDesc.cacheLoadMany(context.property, bc, parentId, context.parent.isReadOnly())) {
|
||||
// we loaded the bean from cache
|
||||
list.remove(bc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
context.parent.getEbeanServer().loadMany(req);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DLoadWeakList<T> implements DLoadList<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DLoadWeakList.class);
|
||||
|
||||
protected final ArrayList<WeakReference<T>> list = new ArrayList<WeakReference<T>>();
|
||||
|
||||
protected int removedFromTop;
|
||||
|
||||
protected DLoadWeakList() {
|
||||
|
||||
}
|
||||
|
||||
public int add(T e) {
|
||||
synchronized (this) {
|
||||
int i = list.size();
|
||||
list.add(new WeakReference<T>(e));
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEntry(int position) {
|
||||
synchronized (this) {
|
||||
WeakReference<T> wref = list.get(position);
|
||||
if (wref == null) {
|
||||
logger.warn("removeEntry found no WeakReference for position[" + position + "]");
|
||||
} else {
|
||||
// just set the entry to null
|
||||
list.set(position, null);
|
||||
T object = wref.get();
|
||||
if (object == null) {
|
||||
logger.warn("removeEntry found no Object held by WeakReference for position[" + position + "]");
|
||||
}
|
||||
}
|
||||
if (position == removedFromTop) {
|
||||
removedFromTop++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<T> getNextBatch(int batchSize) {
|
||||
if (removedFromTop >= list.size()){
|
||||
return new ArrayList<T>(0);
|
||||
}
|
||||
return getLoadBatch(removedFromTop, batchSize, true);
|
||||
}
|
||||
|
||||
public List<T> getLoadBatch(int position, int batchSize) {
|
||||
return getLoadBatch(position, batchSize, false);
|
||||
}
|
||||
|
||||
private List<T> getLoadBatch(int position, int batchSize, boolean ignoreMissing) {
|
||||
|
||||
synchronized (this) {
|
||||
if (batchSize < 1) {
|
||||
throw new RuntimeException("batchSize " + batchSize + " < 1 ??!!");
|
||||
}
|
||||
|
||||
ArrayList<T> batch = new ArrayList<T>();
|
||||
|
||||
if (!addObjectToBatchAt(batch, position) && !ignoreMissing) {
|
||||
String msg = "getLoadBatch position[" + position + "] didn't find a bean in the list?";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
|
||||
for (int i = position; i < list.size(); i++) {
|
||||
addObjectToBatchAt(batch, i);
|
||||
if (batch.size() == batchSize) {
|
||||
// found enough beans going forward
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
|
||||
// search the front of the list to fill our batch
|
||||
for (int i = removedFromTop; i < position; i++) {
|
||||
addObjectToBatchAt(batch, i);
|
||||
if (batch.size() == batchSize) {
|
||||
// found enough beans going forward from start of list
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addObjectToBatchAt(ArrayList<T> batch, int i) {
|
||||
|
||||
boolean found = false;
|
||||
WeakReference<T> wref = list.get(i);
|
||||
if (wref != null) {
|
||||
T object = wref.get();
|
||||
if (object == null) {
|
||||
logger.warn("Bean is null from weak reference");
|
||||
} else {
|
||||
found = true;
|
||||
batch.add(object);
|
||||
}
|
||||
// set it to null saying we have loaded this one
|
||||
list.set(i, null);
|
||||
}
|
||||
if (i == removedFromTop) {
|
||||
removedFromTop++;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import java.util.Set;
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.FetchConfig;
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.OrderBy.Property;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionFactory;
|
||||
@@ -187,8 +186,7 @@ public class OrmQueryProperties implements Serializable {
|
||||
if (filterMany == null){
|
||||
return null;
|
||||
}
|
||||
filterMany.trimPath(trimPath);
|
||||
return filterMany;
|
||||
return filterMany.trimPath(trimPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,11 +246,7 @@ public class OrmQueryProperties implements Serializable {
|
||||
}
|
||||
|
||||
if (orderBy != null){
|
||||
List<Property> orderByProps = orderBy.getProperties();
|
||||
for (int i = 0; i < orderByProps.size(); i++) {
|
||||
orderByProps.get(i).trim(path);
|
||||
}
|
||||
query.setOrder(orderBy);
|
||||
query.setOrder(orderBy.copyWithTrim(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,13 +33,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
|
||||
private static final long serialVersionUID = -6992345500247035947L;
|
||||
|
||||
private final ArrayList<SpiExpression> list = new ArrayList<SpiExpression>();
|
||||
protected final ArrayList<SpiExpression> list = new ArrayList<SpiExpression>();
|
||||
|
||||
private final Query<T> query;
|
||||
protected final Query<T> query;
|
||||
|
||||
private final ExpressionList<T> parentExprList;
|
||||
protected final ExpressionList<T> parentExprList;
|
||||
|
||||
private transient ExpressionFactory expr;
|
||||
protected transient ExpressionFactory expr;
|
||||
|
||||
private final String exprLang;
|
||||
private final String listAndStart;
|
||||
@@ -69,7 +69,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public void trimPath(int prefixTrim) {
|
||||
public SpiExpressionList<?> trimPath(int prefixTrim) {
|
||||
throw new RuntimeException("Only allowed on FilterExpressionList");
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.PagingList;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.QueryListener;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionList;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
|
||||
|
||||
public class FilterExpressionList<T> extends DefaultExpressionList<T> {
|
||||
@@ -31,8 +32,8 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
|
||||
this.rootQuery = rootQuery;
|
||||
}
|
||||
|
||||
public void trimPath(int prefixTrim) {
|
||||
pathPrefix.trimPath(prefixTrim);
|
||||
public SpiExpressionList<?> trimPath(int prefixTrim) {
|
||||
return new FilterExpressionList<T>(pathPrefix.trimPath(prefixTrim), expr, rootQuery);
|
||||
}
|
||||
|
||||
public FilterExprPath getPathPrefix() {
|
||||
|
||||
Reference in New Issue
Block a user