diff --git a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java index c67f16616..4f6f9362a 100644 --- a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java @@ -1,5 +1,10 @@ package com.avaje.ebean.bean; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.ValuePair; + +import javax.persistence.EntityNotFoundException; +import javax.persistence.PersistenceException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; @@ -11,12 +16,6 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import javax.persistence.EntityNotFoundException; -import javax.persistence.PersistenceException; - -import com.avaje.ebean.Ebean; -import com.avaje.ebean.ValuePair; - /** * This is the object added to every entity bean using byte code enhancement. *

@@ -92,6 +91,8 @@ public final class EntityBeanIntercept implements Serializable { private int lazyLoadProperty = -1; + private Object ownerId; + /** * Create a intercept with a given entity. *

@@ -349,11 +350,22 @@ public final class EntityBeanIntercept implements Serializable { * lazy loading and this bean might not be used by the client code at all. * Instead we will fail as soon as the client code tries to use this bean. *

+ * @param lazyLoadPropertyIndex the property that is expected to be loaded */ - public void checkLazyLoadFailure() { - if (lazyLoadProperty != -1) { - this.lazyLoadFailure = true; + public boolean isLazyLoadFailure(int lazyLoadPropertyIndex) { + if (lazyLoadProperty != -1 || !isLoadedProperty(lazyLoadPropertyIndex)) { + lazyLoadFailure = true; + return true; } + lazyLoadFailure = false; + return false; + } + + /** + * Set the Id of the owner bean. + */ + public void setOwnerId(Object ownerId) { + this.ownerId = ownerId; } /** @@ -748,7 +760,7 @@ public final class EntityBeanIntercept implements Serializable { if (lazyLoadFailure) { // failed when batch lazy loaded by another bean in the batch - throw new EntityNotFoundException("Bean has been deleted - lazy loading failed"); + throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted"); } if (lazyLoadProperty == -1) { @@ -763,7 +775,7 @@ public final class EntityBeanIntercept implements Serializable { if (lazyLoadFailure) { // failed when lazy loading this bean - throw new EntityNotFoundException("Bean has been deleted - lazy loading failed"); + throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted."); } // bean should be loaded and intercepting now. setLoaded() has diff --git a/src/main/java/com/avaje/ebeaninternal/api/LoadBeanRequest.java b/src/main/java/com/avaje/ebeaninternal/api/LoadBeanRequest.java index 712aebbd7..caeb2ccb3 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/LoadBeanRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/api/LoadBeanRequest.java @@ -4,6 +4,8 @@ import com.avaje.ebean.bean.EntityBean; import com.avaje.ebean.bean.EntityBeanIntercept; import com.avaje.ebeaninternal.server.core.OrmQueryRequest; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -13,10 +15,14 @@ import java.util.List; */ public class LoadBeanRequest extends LoadRequest { + private static final Logger logger = LoggerFactory.getLogger(LoadBeanRequest.class); + private final List batch; private final LoadBeanBuffer loadBuffer; + private final int lazyLoadPropertyIndex; + private final String lazyLoadProperty; private final boolean loadCache; @@ -24,21 +30,24 @@ public class LoadBeanRequest extends LoadRequest { /** * Construct for lazy load request. */ - public LoadBeanRequest(LoadBeanBuffer LoadBuffer, String lazyLoadProperty, boolean loadCache) { - this(LoadBuffer, null, true, lazyLoadProperty, loadCache); + public LoadBeanRequest(LoadBeanBuffer LoadBuffer, int lazyLoadPropertyIndex, String lazyLoadProperty, boolean loadCache) { + this(LoadBuffer, null, true, lazyLoadPropertyIndex, lazyLoadProperty, loadCache); } /** * Construct for secondary query. */ public LoadBeanRequest(LoadBeanBuffer LoadBuffer, OrmQueryRequest parentRequest) { - this(LoadBuffer, parentRequest, false, null, false); + this(LoadBuffer, parentRequest, false, -1, null, false); } - private LoadBeanRequest(LoadBeanBuffer loadBuffer, OrmQueryRequest parentRequest, boolean lazy, String lazyLoadProperty, boolean loadCache) { + private LoadBeanRequest(LoadBeanBuffer loadBuffer, OrmQueryRequest parentRequest, boolean lazy, + int lazyLoadPropertyIndex, String lazyLoadProperty, boolean loadCache) { + super(parentRequest, lazy); this.loadBuffer = loadBuffer; this.batch = loadBuffer.getBatch(); + this.lazyLoadPropertyIndex = lazyLoadPropertyIndex; this.lazyLoadProperty = lazyLoadProperty; this.loadCache = loadCache; } @@ -143,10 +152,20 @@ public class LoadBeanRequest extends LoadRequest { } } - for (int i = 0; i < batch.size(); i++) { - // Check if the underlying row in DB was deleted. Mark this bean as 'failed' if - // necessary but allow processing to continue until it is accessed by client code - batch.get(i).checkLazyLoadFailure(); + if (lazyLoadPropertyIndex > -1) { + // this is a lazy loading query so check for lazy loading failure (due to deleted rows) + for (int i = 0; i < batch.size(); i++) { + // check if the underlying row in DB was deleted. Mark the bean as 'failed' if + // necessary but allow processing to continue until it is accessed by client code + EntityBeanIntercept ebi = batch.get(i); + // all beans in the batch should have this property loaded now + if (ebi.isLazyLoadFailure(lazyLoadPropertyIndex)) { + BeanDescriptor desc = loadBuffer.getBeanDescriptor(); + Object beanId = desc.getId(ebi.getOwner()); + ebi.setOwnerId(beanId); + logger.info("Lazy loading unsuccessful for type:" + desc.getName() + " id:" + beanId + " - expecting when bean has been deleted"); + } + } } } } diff --git a/src/main/java/com/avaje/ebeaninternal/api/LoadManyRequest.java b/src/main/java/com/avaje/ebeaninternal/api/LoadManyRequest.java index 25af86df3..e6d918adb 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/LoadManyRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/api/LoadManyRequest.java @@ -183,7 +183,7 @@ public class LoadManyRequest extends LoadRequest { if (logger.isDebugEnabled()) { EntityBean ownerBean = bc.getOwnerBean(); Object parentId = desc.getId(ownerBean); - logger.debug("BeanCollection after lazy load was empty. type[" + ownerBean.getClass() + "] id[" + parentId + "] owner[" + ownerBean + "]"); + logger.debug("BeanCollection after lazy load was empty. type:" + ownerBean.getClass().getName() + " id:" + parentId + " owner:" + ownerBean); } } else if (isLoadCache()) { Object parentId = desc.getId(bc.getOwnerBean()); diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java index 9fb43dee4..3d9e82118 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java @@ -85,7 +85,7 @@ public class DefaultBeanLoader { SpiQuery query = loadRequest.createQuery(server, batchSize); - executeLazyLoadQuery(loadRequest, query); + executeQuery(loadRequest, query); loadRequest.postLoad(); @@ -214,7 +214,7 @@ public class DefaultBeanLoader { query.where().idIn(idList); } - List list = executeLazyLoadQuery(loadRequest, query); + List list = executeQuery(loadRequest, query); loadRequest.postLoad(list); @@ -225,7 +225,7 @@ public class DefaultBeanLoader { /** * Execute the lazy load query taking into account MySql transaction oddness. */ - private List executeLazyLoadQuery(LoadRequest loadRequest, SpiQuery query) { + private List executeQuery(LoadRequest loadRequest, SpiQuery query) { if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) { // MySql - we need a different transaction to execute the secondary query SpiTransaction extraTxn = server.createQueryTransaction(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java index 254fd6d78..fd121d517 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java @@ -190,7 +190,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex } } - LoadBeanRequest req = new LoadBeanRequest(this, ebi.getLazyLoadProperty(), context.hitCache); + LoadBeanRequest req = new LoadBeanRequest(this, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty(), context.hitCache); context.desc.getEbeanServer().loadBean(req); }