#2376 - When Lazy load of soft deleted bean - javax.persistence.EntityNotFoundException: Bean not found during lazy load or refresh. id[*] type[class *]

This commit is contained in:
Rob Bygrave committed 2021-09-16 23:01:04 +12:00
1 parent b262c2e19d
commit 3865fc8ffd
5 files changed
+71 -16

No files matched your search

@@ -175,14 +175,12 @@ final class DefaultBeanLoader {
// need a new PersistenceContext for REFRESH // need a new PersistenceContext for REFRESH
pc = null; pc = null;
} }
BeanDescriptor<?> desc = server.descriptor(bean.getClass()); BeanDescriptor<?> desc = server.descriptor(bean.getClass());
if (EntityType.EMBEDDED == desc.entityType()) { if (EntityType.EMBEDDED == desc.entityType()) {
// lazy loading on an embedded bean property // lazy loading on an embedded bean property
EntityBean embeddedOwner = (EntityBean) ebi.getEmbeddedOwner(); EntityBean embeddedOwner = (EntityBean) ebi.getEmbeddedOwner();
refreshBeanInternal(embeddedOwner, mode, ebi.getEmbeddedOwnerIndex()); refreshBeanInternal(embeddedOwner, mode, ebi.getEmbeddedOwnerIndex());
} }
Object id = desc.getId(bean); Object id = desc.getId(bean);
if (pc == null) { if (pc == null) {
// a reference with no existing persistenceContext // a reference with no existing persistenceContext
@@ -202,17 +200,16 @@ final class DefaultBeanLoader {
} }
} }
} }
SpiQuery<?> query = server.createQuery(desc.type()); SpiQuery<?> query = server.createQuery(desc.type());
query.setLazyLoadProperty(ebi.getLazyLoadProperty()); query.setLazyLoadProperty(ebi.getLazyLoadProperty());
if (draft) { if (draft) {
query.asDraft(); query.asDraft();
} else {
query.setIncludeSoftDeletes();
} }
if (embeddedOwnerIndex > -1) { if (embeddedOwnerIndex > -1) {
query.select(ebi.getProperty(embeddedOwnerIndex)); query.select(ebi.getProperty(embeddedOwnerIndex));
} }
// don't collect AutoTune usage profiling information // don't collect AutoTune usage profiling information
// as we just copy the data out of these fetched beans // as we just copy the data out of these fetched beans
// and put the data into the original bean // and put the data into the original bean
@@ -1,6 +1,7 @@
package org.tests.cache.personinfo; package org.tests.cache.personinfo;
import io.ebean.annotation.Cache; import io.ebean.annotation.Cache;
import io.ebean.annotation.SoftDelete;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
@@ -16,6 +17,9 @@ public class PersonCacheInfo {
private String name; private String name;
@SoftDelete
boolean deleted;
public PersonCacheInfo(String personId, String name) { public PersonCacheInfo(String personId, String name) {
this.personId = personId; this.personId = personId;
this.name = name; this.name = name;
@@ -36,4 +40,13 @@ public class PersonCacheInfo {
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public boolean deleted() {
return deleted;
}
public PersonCacheInfo deleted(boolean deleted) {
this.deleted = deleted;
return this;
}
} }
@@ -21,15 +21,12 @@ public class PersonCacheTests {
private final List<Object> ids = Arrays.asList("E001", "E002", "E003"); private final List<Object> ids = Arrays.asList("E001", "E002", "E003");
private ServerCache beanCacheInfo = DB.getDefault().cacheManager().beanCache(PersonCacheInfo.class); private final ServerCache beanCacheInfo = DB.getDefault().cacheManager().beanCache(PersonCacheInfo.class);
private ServerCache beanCacheEmail = DB.getDefault().cacheManager().beanCache(PersonCacheEmail.class); private final ServerCache beanCacheEmail = DB.getDefault().cacheManager().beanCache(PersonCacheEmail.class);
private final ServerCacheRegion region = DB.getDefault().cacheManager().region("email");
private ServerCacheRegion region = DB.getDefault().cacheManager().region("email");
private void insert(int id, String email) { private void insert(int id, String email) {
PersonCacheInfo person = new PersonCacheInfo("P00" + id, "P00" + id); PersonCacheInfo person = new PersonCacheInfo("P00" + id, "P00" + id);
PersonCacheEmail personEmail = new PersonCacheEmail("E00" + id, email); PersonCacheEmail personEmail = new PersonCacheEmail("E00" + id, email);
personEmail.setPersonInfo(person); personEmail.setPersonInfo(person);
@@ -38,7 +35,6 @@ public class PersonCacheTests {
} }
private void addTestData() { private void addTestData() {
insert(1, "testA"); insert(1, "testA");
insert(2, "testB"); insert(2, "testB");
insert(3, "testC"); insert(3, "testC");
@@ -0,0 +1,49 @@
package org.tests.cache.personinfo;
import io.ebean.DB;
import io.ebean.test.LoggedSql;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
class TestCacheSoftDeleteLazyLoad {
private final String personEmailId = "SDLL-Email-01";
private final String personId = "SDLL-Person-01";
void setup(){
PersonCacheInfo person = new PersonCacheInfo(personId , "Hello");
PersonCacheEmail personEmail = new PersonCacheEmail(personEmailId, "hello@foo.com");
personEmail.setPersonInfo(person);
DB.save(person);
DB.save(personEmail);
}
@Test
void softDeleteReferencedBean_when_lazyLoad_expect() {
setup();
// load cache
DB.find(PersonCacheEmail.class, personEmailId);
// soft delete our bean referenced by email
PersonCacheInfo info = DB.find(PersonCacheInfo.class, personId);
DB.delete(info);
// load from cache (still references a now soft deleted bean)
PersonCacheEmail email2 = DB.find(PersonCacheEmail.class, personEmailId);
assert email2 != null;
LoggedSql.start();
PersonCacheInfo personInfo = email2.getPersonInfo();
assertThat(personInfo).isNotNull();
assertThat(personInfo.deleted()).isTrue(); // lazy load includes soft deletes
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0))
.contains(" from person_cache_info t0 where t0.person_id = ?")
.doesNotContain("and t0.deleted =");
}
}
@@ -79,11 +79,11 @@
<logger name="io.ebean.docker" level="TRACE"/> <logger name="io.ebean.docker" level="TRACE"/>
<!-- <logger name="io.ebean.DDL" level="DEBUG"/>--> <!-- <logger name="io.ebean.DDL" level="DEBUG"/>-->
<!-- <logger name="io.ebean.SQL" level="TRACE"/>--> <logger name="io.ebean.SQL" level="TRACE"/>
<!-- <logger name="io.ebean.TXN" level="TRACE"/>--> <logger name="io.ebean.TXN" level="TRACE"/>
<!-- <logger name="io.ebean.SUM" level="TRACE"/>--> <logger name="io.ebean.SUM" level="TRACE"/>
<!-- <logger name="io.ebean.cache" level="TRACE"/>--> <logger name="io.ebean.cache" level="TRACE"/>
<!-- <logger name="io.ebean.cache.REGION" level="TRACE"/>--> <!-- <logger name="io.ebean.cache.REGION" level="TRACE"/>-->
<!-- <logger name="io.ebean.cache.TABLEMOD" level="TRACE"/>--> <!-- <logger name="io.ebean.cache.TABLEMOD" level="TRACE"/>-->