#462 - When fetching, collections can get populated with too many entities - Fix

This commit is contained in:
Robin Bygrave
2016-02-13 00:43:47 +13:00
parent 62aca1e77b
commit 8a8b36ec1e
12 changed files with 68 additions and 29 deletions
@@ -125,6 +125,11 @@ public interface BeanCollection<E> extends Serializable {
*/
void internalAdd(Object bean);
/**
* Add the bean with a check to see if it is already contained.
*/
void internalAddWithCheck(Object bean);
/**
* Return the number of elements in the List Set or Map.
*/
@@ -1,5 +1,9 @@
package com.avaje.ebean.common;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@@ -8,17 +12,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* List capable of lazy loading.
*/
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E>, BeanCollectionAdd {
private static final long serialVersionUID = 1L;
/**
* The underlying List implementation.
*/
@@ -74,6 +74,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
}
@Override
public void internalAddWithCheck(Object bean) {
if (list == null || !list.contains(bean)) {
internalAdd(bean);
}
}
public boolean checkEmptyLazyLoad() {
if (list == null) {
list = new ArrayList<E>();
@@ -99,11 +106,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (list == null) {
@@ -134,7 +141,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
public Collection<E> getActualDetails() {
return list;
}
@Override
public Collection<?> getActualEntries() {
return list;
@@ -66,7 +66,18 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
map.put((K) key, (E) bean);
}
}
public void internalPutWithCheck(Object key, Object bean) {
if (map == null || !map.containsKey(key)) {
internalPut(key, bean);
}
}
@Override
public void internalAddWithCheck(Object bean) {
throw new RuntimeException("Not allowed for map");
}
public void internalAdd(Object bean) {
throw new RuntimeException("Not allowed for map");
}
@@ -1,15 +1,15 @@
package com.avaje.ebean.common;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* Set capable of lazy loading.
*/
@@ -57,6 +57,13 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
set.add((E) bean);
}
@Override
public void internalAddWithCheck(Object bean) {
if (set == null || !set.contains(bean)) {
internalAdd(bean);
}
}
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (set == null) {
@@ -107,11 +114,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (set == null) {
@@ -42,7 +42,7 @@ public interface BeanCollectionHelp<T> {
/**
* Add a bean to the List Set or Map.
*/
void add(BeanCollection<?> collection, EntityBean bean);
void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck);
/**
* Create a lazy loading proxy for a List Set or Map.
@@ -46,8 +46,12 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
* Internal add bypassing any modify listening.
*/
@Override
public void add(BeanCollection<?> collection, EntityBean bean) {
collection.internalAdd(bean);
public void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck) {
if (withCheck) {
collection.internalAddWithCheck(bean);
} else {
collection.internalAdd(bean);
}
}
@Override
@@ -108,13 +108,14 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
}
@Override
public void add(BeanCollection<?> collection, EntityBean bean) {
public void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck) {
if (bean == null) {
((BeanMap<?, ?>) collection).internalPutNull();
} else {
Object keyValue = beanProperty.getValueIntercept(bean);
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
BeanMap<?, ?> map = ((BeanMap<?, ?>) collection);
map.internalPutWithCheck(keyValue, bean);
}
}
@@ -182,13 +182,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
/**
* Add the bean to the appropriate collection on the parent bean.
*/
public void addBeanToCollectionWithCreate(EntityBean parentBean, EntityBean detailBean) {
public void addBeanToCollectionWithCreate(EntityBean parentBean, EntityBean detailBean, boolean withCheck) {
BeanCollection<?> bc = (BeanCollection<?>) super.getValue(parentBean);
if (bc == null) {
bc = help.createEmpty(parentBean);
setValue(parentBean, bc);
}
help.add(bc, detailBean);
help.add(bc, detailBean, withCheck);
}
/**
@@ -416,7 +416,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
}
public void add(BeanCollection<?> collection, EntityBean bean) {
help.add(collection, bean);
help.add(collection, bean, false);
}
/**
@@ -61,8 +61,12 @@ public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
}
}
public void add(BeanCollection<?> collection, EntityBean bean) {
collection.internalAdd(bean);
public void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck) {
if (withCheck) {
collection.internalAddWithCheck(bean);
} else {
collection.internalAdd(bean);
}
}
@Override
@@ -399,7 +399,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
}
// add the loadedBean to the appropriate collection of lazyLoadParentBean
lazyLoadManyProperty.addBeanToCollectionWithCreate(lazyLoadParentBean, bean);
lazyLoadManyProperty.addBeanToCollectionWithCreate(lazyLoadParentBean, bean, true);
}
}
@@ -542,7 +542,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
while (hasNext()) {
EntityBean bean = next();
help.add(collection, bean);
help.add(collection, bean, false);
}
updateExecutionStatistics();
@@ -347,7 +347,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
return localBean;
} else {
if (lazyLoadParentId != null && newBean) {
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId);
}
return contextBean;
@@ -24,7 +24,7 @@ public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
// being set to the parentBean directly
EntityBean detailBean = super.load(cquery, null, null);
// initialise the collection and add detailBean if it is not null
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean);
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, false);
return detailBean;
}