mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-28 16:08:04 +00:00
#919 - io.ebean package initial
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package io.ebeaninternal.server.loadcontext;
|
||||
|
||||
import io.ebean.FetchConfig;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.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 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.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;
|
||||
}
|
||||
|
||||
int queryBatchSize = queryProps.getQueryFetchBatch();
|
||||
if (queryBatchSize == -1) {
|
||||
return batchSize;
|
||||
|
||||
} else if (queryBatchSize == 0) {
|
||||
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.isQueryAll()) {
|
||||
return firstBatchSize;
|
||||
}
|
||||
|
||||
int lazyBatchSize = fetchConfig.getLazyBatchSize();
|
||||
return (lazyBatchSize > 1) ? lazyBatchSize : defaultBatchSize;
|
||||
}
|
||||
|
||||
protected PersistenceContext getPersistenceContext() {
|
||||
return parent.getPersistenceContext();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package io.ebeaninternal.server.loadcontext;
|
||||
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.api.LoadBeanBuffer;
|
||||
import io.ebeaninternal.api.LoadBeanContext;
|
||||
import io.ebeaninternal.api.LoadBeanRequest;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Default implementation of LoadBeanContext.
|
||||
*/
|
||||
public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
|
||||
private List<LoadBuffer> bufferList;
|
||||
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
public DLoadBeanContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
super(parent, desc, path, defaultBatchSize, queryProps);
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the buffers after a query iterator reset.
|
||||
*/
|
||||
public void clear() {
|
||||
if (bufferList != null) {
|
||||
bufferList.clear();
|
||||
}
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
|
||||
protected void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
|
||||
|
||||
parent.propagateQueryState(query, desc.isDocStoreMapped());
|
||||
query.setParentNode(objectGraphNode);
|
||||
query.setLazyLoadProperty(lazyLoadProperty);
|
||||
if (queryProps != null) {
|
||||
queryProps.configureBeanQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
protected void register(EntityBeanIntercept ebi) {
|
||||
|
||||
if (currentBuffer.isFull()) {
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
ebi.setBeanLoader(currentBuffer, getPersistenceContext());
|
||||
currentBuffer.add(ebi);
|
||||
}
|
||||
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
LoadBuffer buffer = new LoadBuffer(this, size);
|
||||
if (bufferList != null) {
|
||||
bufferList.add(buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach) {
|
||||
|
||||
if (!queryFetch) {
|
||||
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
|
||||
}
|
||||
synchronized (this) {
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
LoadBeanRequest req = new LoadBeanRequest(loadBuffer, parentRequest);
|
||||
parent.getEbeanServer().loadBean(req);
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (forEach) {
|
||||
clear();
|
||||
} else {
|
||||
// this is only run once - secondary query is a one shot deal
|
||||
this.bufferList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
public LoadBuffer(DLoadBeanContext context, int batchSize) {
|
||||
this.context = context;
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<>(batchSize);
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean isFull() {
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the bean to the load buffer.
|
||||
*/
|
||||
public void add(EntityBeanIntercept ebi) {
|
||||
if (persistenceContext == null) {
|
||||
// get persistenceContext from first loaded bean into the buffer
|
||||
persistenceContext = ebi.getPersistenceContext();
|
||||
}
|
||||
list.add(ebi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntityBeanIntercept> getBatch() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return context.serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullPath() {
|
||||
return context.fullPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return context.desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
@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.cacheBeanLoad(ebi, persistenceContext)) {
|
||||
// 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 batchEbi = iterator.next();
|
||||
if (batchEbi != ebi && context.desc.cacheBeanLoad(batchEbi, persistenceContext)) {
|
||||
// bean successfully loaded from L2 cache so remove from batch load
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoadBeanRequest req = new LoadBeanRequest(this, ebi.getLazyLoadProperty(), context.hitCache);
|
||||
context.desc.getEbeanServer().loadBean(req);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
package io.ebeaninternal.server.loadcontext;
|
||||
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.CallStack;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.ObjectGraphOrigin;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.api.LoadContext;
|
||||
import io.ebeaninternal.api.LoadSecondaryQuery;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiQuerySecondary;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Default implementation of LoadContext.
|
||||
*/
|
||||
public class DLoadContext implements LoadContext {
|
||||
|
||||
private final SpiEbeanServer ebeanServer;
|
||||
|
||||
private final BeanDescriptor<?> rootDescriptor;
|
||||
|
||||
private final Map<String, DLoadBeanContext> beanMap = new HashMap<>();
|
||||
private final Map<String, DLoadManyContext> manyMap = new HashMap<>();
|
||||
|
||||
private final DLoadBeanContext rootBeanContext;
|
||||
|
||||
private final boolean asDraft;
|
||||
private final Timestamp asOf;
|
||||
private final Boolean readOnly;
|
||||
private final boolean excludeBeanCache;
|
||||
private final int defaultBatchSize;
|
||||
private final boolean disableLazyLoading;
|
||||
private final boolean disableReadAudit;
|
||||
private final boolean includeSoftDeletes;
|
||||
protected final boolean useDocStore;
|
||||
|
||||
/**
|
||||
* The path relative to the root of the object graph.
|
||||
*/
|
||||
private final String relativePath;
|
||||
private final ObjectGraphOrigin origin;
|
||||
private final boolean useProfiling;
|
||||
|
||||
private final Map<String, ObjectGraphNode> nodePathMap = new HashMap<>();
|
||||
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
private List<OrmQueryProperties> secQuery;
|
||||
|
||||
private Object tenantId;
|
||||
|
||||
/**
|
||||
* Construct for use with JSON marshalling (doc store).
|
||||
*/
|
||||
public DLoadContext(BeanDescriptor<?> rootDescriptor, PersistenceContext persistenceContext) {
|
||||
|
||||
this.useDocStore = true;
|
||||
this.rootDescriptor = rootDescriptor;
|
||||
this.ebeanServer = rootDescriptor.getEbeanServer();
|
||||
this.persistenceContext = persistenceContext;
|
||||
this.origin = initOrigin();
|
||||
this.defaultBatchSize = 100;
|
||||
this.excludeBeanCache = false;
|
||||
this.asDraft = false;
|
||||
this.asOf = null;
|
||||
this.readOnly = false;
|
||||
this.disableLazyLoading = false;
|
||||
this.disableReadAudit = false;
|
||||
this.includeSoftDeletes = false;
|
||||
this.relativePath = null;
|
||||
this.useProfiling = false;
|
||||
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null);
|
||||
}
|
||||
|
||||
private ObjectGraphOrigin initOrigin() {
|
||||
CallStack callStack = ebeanServer.createCallStack();
|
||||
return new ObjectGraphOrigin(0, callStack, rootDescriptor.getFullName());
|
||||
}
|
||||
|
||||
public DLoadContext(OrmQueryRequest<?> request, SpiQuerySecondary secondaryQueries) {
|
||||
|
||||
this.tenantId = request.getTransaction().getTenantId();
|
||||
this.persistenceContext = request.getPersistenceContext();
|
||||
this.ebeanServer = request.getServer();
|
||||
this.defaultBatchSize = request.getLazyLoadBatchSize();
|
||||
this.rootDescriptor = request.getBeanDescriptor();
|
||||
|
||||
SpiQuery<?> query = request.getQuery();
|
||||
this.useDocStore = query.isUseDocStore();
|
||||
this.asOf = query.getAsOf();
|
||||
this.asDraft = query.isAsDraft();
|
||||
this.includeSoftDeletes = query.isIncludeSoftDeletes();
|
||||
this.readOnly = query.isReadOnly();
|
||||
this.disableReadAudit = query.isDisableReadAudit();
|
||||
this.disableLazyLoading = query.isDisableLazyLoading();
|
||||
this.excludeBeanCache = query.isExcludeBeanCache();
|
||||
this.useProfiling = query.getProfilingListener() != null;
|
||||
|
||||
ObjectGraphNode parentNode = query.getParentNode();
|
||||
if (parentNode != null) {
|
||||
this.origin = parentNode.getOriginQueryPoint();
|
||||
this.relativePath = parentNode.getPath();
|
||||
} else {
|
||||
this.origin = null;
|
||||
this.relativePath = null;
|
||||
}
|
||||
|
||||
// initialise rootBeanContext after origin and relativePath have been set
|
||||
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null);
|
||||
|
||||
registerSecondaryQueries(secondaryQueries);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the +query and +lazy secondary queries with their appropriate LoadBeanContext or LoadManyContext.
|
||||
*/
|
||||
private void registerSecondaryQueries(SpiQuerySecondary secondaryQueries) {
|
||||
|
||||
this.secQuery = secondaryQueries.getQueryJoins();
|
||||
if (secQuery != null) {
|
||||
for (OrmQueryProperties pathProperties : secQuery) {
|
||||
registerSecondaryQuery(pathProperties);
|
||||
}
|
||||
}
|
||||
|
||||
List<OrmQueryProperties> lazyJoins = secondaryQueries.getLazyJoins();
|
||||
if (lazyJoins != null) {
|
||||
for (OrmQueryProperties lazyJoin : lazyJoins) {
|
||||
registerSecondaryQuery(lazyJoin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the load context at this path with OrmQueryProperties which is
|
||||
* used to build the appropriate query for +query or +lazy loading.
|
||||
*/
|
||||
private void registerSecondaryQuery(OrmQueryProperties props) {
|
||||
|
||||
ElPropertyValue elGetValue = rootDescriptor.getElGetValue(props.getPath());
|
||||
|
||||
boolean many = elGetValue.getBeanProperty().containsMany();
|
||||
registerSecondaryNode(many, props);
|
||||
}
|
||||
|
||||
protected boolean isExcludeBeanCache() {
|
||||
return excludeBeanCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum batch size when using QueryIterator with query joins.
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(int defaultQueryBatch) {
|
||||
|
||||
if (secQuery == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int maxBatch = 0;
|
||||
for (OrmQueryProperties aSecQuery : secQuery) {
|
||||
int batchSize = aSecQuery.getQueryFetchBatch();
|
||||
if (batchSize == 0) {
|
||||
batchSize = defaultQueryBatch;
|
||||
}
|
||||
maxBatch = Math.max(maxBatch, batchSize);
|
||||
}
|
||||
return maxBatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all the secondary queries.
|
||||
*/
|
||||
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, boolean forEach) {
|
||||
|
||||
if (secQuery != null) {
|
||||
for (OrmQueryProperties aSecQuery : secQuery) {
|
||||
LoadSecondaryQuery load = getLoadSecondaryQuery(aSecQuery.getPath());
|
||||
load.loadSecondaryQuery(parentRequest, forEach);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the LoadBeanContext or LoadManyContext for the given path.
|
||||
*/
|
||||
private LoadSecondaryQuery getLoadSecondaryQuery(String path) {
|
||||
LoadSecondaryQuery beanLoad = beanMap.get(path);
|
||||
if (beanLoad == null) {
|
||||
beanLoad = manyMap.get(path);
|
||||
}
|
||||
return beanLoad;
|
||||
}
|
||||
|
||||
public ObjectGraphNode getObjectGraphNode(String path) {
|
||||
|
||||
ObjectGraphNode node = nodePathMap.get(path);
|
||||
if (node == null) {
|
||||
node = createObjectGraphNode(path);
|
||||
nodePathMap.put(path, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private ObjectGraphNode createObjectGraphNode(String path) {
|
||||
|
||||
if (relativePath != null) {
|
||||
if (path == null) {
|
||||
path = relativePath;
|
||||
} else {
|
||||
path = relativePath + "." + path;
|
||||
}
|
||||
}
|
||||
return new ObjectGraphNode(origin, path);
|
||||
}
|
||||
|
||||
protected String getFullPath(String path) {
|
||||
if (relativePath == null) {
|
||||
return path;
|
||||
} else {
|
||||
return relativePath + "." + path;
|
||||
}
|
||||
}
|
||||
|
||||
protected SpiEbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent state which defines the sharedInstance and readOnly status
|
||||
* which needs to be propagated to other beans and collections.
|
||||
*/
|
||||
protected Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
public void resetPersistenceContext(PersistenceContext persistenceContext) {
|
||||
this.persistenceContext = persistenceContext;
|
||||
// clear the load contexts for beans and beanCollections
|
||||
for (DLoadBeanContext beanContext : beanMap.values()) {
|
||||
beanContext.clear();
|
||||
}
|
||||
for (DLoadManyContext manyContext : manyMap.values()) {
|
||||
manyContext.clear();
|
||||
}
|
||||
this.rootBeanContext.clear();
|
||||
}
|
||||
|
||||
public void register(String path, EntityBeanIntercept ebi) {
|
||||
getBeanContext(path).register(ebi);
|
||||
}
|
||||
|
||||
public void register(String path, BeanCollection<?> bc) {
|
||||
getManyContext(path).register(bc);
|
||||
}
|
||||
|
||||
protected DLoadBeanContext getBeanContext(String path) {
|
||||
if (path == null) {
|
||||
return rootBeanContext;
|
||||
}
|
||||
DLoadBeanContext beanContext = beanMap.get(path);
|
||||
if (beanContext == null) {
|
||||
beanContext = createBeanContext(path, defaultBatchSize, null);
|
||||
beanMap.put(path, beanContext);
|
||||
}
|
||||
return beanContext;
|
||||
}
|
||||
|
||||
private void registerSecondaryNode(boolean many, OrmQueryProperties props) {
|
||||
|
||||
int batchSize;
|
||||
if (props.isQueryFetch()) {
|
||||
batchSize = 100;
|
||||
} else {
|
||||
int lazyJoinBatch = props.getLazyFetchBatch();
|
||||
batchSize = lazyJoinBatch > 0 ? lazyJoinBatch : defaultBatchSize;
|
||||
}
|
||||
|
||||
String path = props.getPath();
|
||||
if (many) {
|
||||
manyMap.put(path, createManyContext(path, batchSize, props));
|
||||
} else {
|
||||
beanMap.put(path, createBeanContext(path, batchSize, props));
|
||||
}
|
||||
}
|
||||
|
||||
protected DLoadManyContext getManyContext(String path) {
|
||||
if (path == null) {
|
||||
throw new RuntimeException("path is null?");
|
||||
}
|
||||
DLoadManyContext ctx = manyMap.get(path);
|
||||
if (ctx == null) {
|
||||
ctx = createManyContext(path, defaultBatchSize, null);
|
||||
manyMap.put(path, ctx);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
private DLoadManyContext createManyContext(String path, int batchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
BeanPropertyAssocMany<?> p = (BeanPropertyAssocMany<?>) getBeanProperty(rootDescriptor, path);
|
||||
|
||||
return new DLoadManyContext(this, p, path, batchSize, queryProps);
|
||||
}
|
||||
|
||||
private DLoadBeanContext createBeanContext(String path, int batchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
BeanPropertyAssoc<?> p = (BeanPropertyAssoc<?>) getBeanProperty(rootDescriptor, path);
|
||||
BeanDescriptor<?> targetDescriptor = p.getTargetDescriptor();
|
||||
|
||||
return new DLoadBeanContext(this, targetDescriptor, path, batchSize, queryProps);
|
||||
}
|
||||
|
||||
private BeanProperty getBeanProperty(BeanDescriptor<?> desc, String path) {
|
||||
return desc.getBeanPropertyFromPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate the original query settings (draft, asOf etc) to the secondary queries.
|
||||
*/
|
||||
public void propagateQueryState(SpiQuery<?> query, boolean docStoreMapped) {
|
||||
if (useDocStore && docStoreMapped) {
|
||||
query.setUseDocStore(true);
|
||||
}
|
||||
if (readOnly != null) {
|
||||
query.setReadOnly(readOnly);
|
||||
}
|
||||
query.setDisableLazyLoading(disableLazyLoading);
|
||||
query.asOf(asOf);
|
||||
if (asDraft) {
|
||||
query.asDraft();
|
||||
}
|
||||
if (includeSoftDeletes) {
|
||||
query.setIncludeSoftDeletes();
|
||||
}
|
||||
if (disableReadAudit) {
|
||||
query.setDisableReadAuditing();
|
||||
}
|
||||
if (useProfiling) {
|
||||
query.setAutoTune(true);
|
||||
}
|
||||
if (tenantId != null) {
|
||||
query.setTenantId(tenantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package io.ebeaninternal.server.loadcontext;
|
||||
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.api.LoadManyBuffer;
|
||||
import io.ebeaninternal.api.LoadManyContext;
|
||||
import io.ebeaninternal.api.LoadManyRequest;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
|
||||
protected final BeanPropertyAssocMany<?> property;
|
||||
|
||||
private final boolean docStoreMapped;
|
||||
|
||||
private List<LoadBuffer> bufferList;
|
||||
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property,
|
||||
String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
|
||||
|
||||
this.property = property;
|
||||
this.docStoreMapped = property.getTargetDescriptor().isDocStoreMapped();
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
}
|
||||
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
LoadBuffer buffer = new LoadBuffer(this, size);
|
||||
if (bufferList != null) {
|
||||
bufferList.add(buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the buffers for a query iterator reset.
|
||||
*/
|
||||
public void clear() {
|
||||
if (bufferList != null) {
|
||||
bufferList.clear();
|
||||
}
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
|
||||
public void configureQuery(SpiQuery<?> query) {
|
||||
|
||||
parent.propagateQueryState(query, docStoreMapped);
|
||||
query.setParentNode(objectGraphNode);
|
||||
if (queryProps != null) {
|
||||
queryProps.configureBeanQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?> getBeanProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return parent.getEbeanServer().getName();
|
||||
}
|
||||
|
||||
public void register(BeanCollection<?> bc) {
|
||||
|
||||
if (currentBuffer.isFull()) {
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
currentBuffer.add(bc);
|
||||
bc.setLoader(currentBuffer);
|
||||
}
|
||||
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach) {
|
||||
|
||||
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);
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forEach) {
|
||||
clear();
|
||||
} else {
|
||||
// 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 PersistenceContext persistenceContext;
|
||||
private final DLoadManyContext context;
|
||||
private final int batchSize;
|
||||
private final List<BeanCollection<?>> list;
|
||||
|
||||
public LoadBuffer(DLoadManyContext context, int batchSize) {
|
||||
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.list = new ArrayList<>(batchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseDocStore() {
|
||||
return context.parent.useDocStore && context.docStoreMapped;
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean isFull() {
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public void add(BeanCollection<?> bc) {
|
||||
list.add(bc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BeanCollection<?>> getBatch() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanPropertyAssocMany<?> getBeanProperty() {
|
||||
return context.property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getObjectGraphNode() {
|
||||
return context.objectGraphNode;
|
||||
}
|
||||
|
||||
@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 persistenceContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullPath() {
|
||||
return context.fullPath;
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
synchronized (this) {
|
||||
boolean useCache = context.hitCache && !onlyIds;
|
||||
if (useCache) {
|
||||
EntityBean ownerBean = bc.getOwnerBean();
|
||||
BeanDescriptor<?> parentDesc = context.desc.getBeanDescriptor(ownerBean.getClass());
|
||||
Object parentId = parentDesc.getId(ownerBean);
|
||||
if (parentDesc.cacheManyPropLoad(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, onlyIds, useCache);
|
||||
context.parent.getEbeanServer().loadMany(req);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package io.ebeaninternal.server.loadcontext;
|
||||
Reference in New Issue
Block a user