From 29f1e63146d368a78f28d74ff228986f708cfe1c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 22 Aug 2014 00:41:12 +1200 Subject: [PATCH] Fix for #186 - Fix for Lazy load when fetched optional ManyToOne bean is null in database --- .../server/query/SqlTreeNodeBean.java | 2 +- .../server/autofetch/TunedQueryInfoTest.java | 197 ++++++++++++++++++ .../TunedQueryWithNullFetchedBeanTest.java | 68 ++++++ 3 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryInfoTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryWithNullFetchedBeanTest.java diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java index 75c9a8f54..f85cf7d97 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -310,7 +310,7 @@ public class SqlTreeNodeBean implements SqlTreeNode { } } - if (parentBean != null && contextBean != null) { + if (parentBean != null) { // set this back to the parentBean nodeBeanProp.setValue(parentBean, contextBean); } diff --git a/src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryInfoTest.java b/src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryInfoTest.java new file mode 100644 index 000000000..b66df26fb --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryInfoTest.java @@ -0,0 +1,197 @@ +package com.avaje.ebeaninternal.server.autofetch; + +import java.util.List; +import java.util.Set; + +import org.avaje.ebeantest.LoggedSqlCollector; +import org.junit.Assert; +import org.junit.Test; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.EbeanServer; +import com.avaje.ebean.Query; +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.bean.EntityBeanIntercept; +import com.avaje.ebean.cache.ServerCacheManager; +import com.avaje.ebeaninternal.api.SpiQuery; +import com.avaje.ebeaninternal.server.autofetch.TunedQueryInfo; +import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail; +import com.avaje.tests.model.basic.Order; +import com.avaje.tests.model.basic.ResetBasicData; + +public class TunedQueryInfoTest extends BaseTestCase { + + EbeanServer server = Ebean.getServer(null); + + private void init() { + + ResetBasicData.reset(); + + ServerCacheManager serverCacheManager = Ebean.getServer(null).getServerCacheManager(); + serverCacheManager.clearAll(); + serverCacheManager.setCaching(Order.class, false); + } + + @Test + public void withSelectNull() { + + init(); + + OrmQueryDetail tunedDetail = new OrmQueryDetail(); + tunedDetail.select(null); + + TunedQueryInfo tunedInfo = new TunedQueryInfo(null, tunedDetail, 0); + + Query query = server.find(Order.class).setId(1); + + tunedInfo.autoFetchTune((SpiQuery)query); + + Order order = query.findUnique(); + EntityBean eb = (EntityBean)order; + EntityBeanIntercept ebi = eb._ebean_getIntercept(); + + Assert.assertTrue(ebi.isFullyLoadedBean()); + + Set loadedPropertyNames = ebi.getLoadedPropertyNames(); + Assert.assertNull(loadedPropertyNames); + + // invoke lazy loading + order.getCustomer(); + } + + + @Test + public void withSelectEmpty() { + + init(); + + OrmQueryDetail tunedDetail = new OrmQueryDetail(); + tunedDetail.select(""); + + TunedQueryInfo tunedInfo = new TunedQueryInfo(null, tunedDetail, 0); + + Query query = server.find(Order.class).setId(1); + + tunedInfo.autoFetchTune((SpiQuery)query); + + Order order = query.findUnique(); + EntityBean eb = (EntityBean)order; + EntityBeanIntercept ebi = eb._ebean_getIntercept(); + + Assert.assertTrue(ebi.isFullyLoadedBean()); + + Set loadedPropertyNames = ebi.getLoadedPropertyNames(); + Assert.assertNull(loadedPropertyNames); + + // invoke lazy loading + order.getCustomer(); + } + + @Test + public void withSelectSomethingThatDoesNotExist() { + + init(); + + OrmQueryDetail tunedDetail = new OrmQueryDetail(); + tunedDetail.select("somethingThatDoesNotExist"); + + TunedQueryInfo tunedInfo = new TunedQueryInfo(null, tunedDetail, 0); + + Query query = server.find(Order.class).setId(1); + + tunedInfo.autoFetchTune((SpiQuery)query); + + LoggedSqlCollector.start(); + + Order order = query.findUnique(); + EntityBean eb = (EntityBean)order; + EntityBeanIntercept ebi = eb._ebean_getIntercept(); + + Assert.assertFalse(ebi.isFullyLoadedBean()); + + // id and any ToMany relationships + Set loadedPropertyNames = ebi.getLoadedPropertyNames(); + Assert.assertNotNull(loadedPropertyNames); + + // invoke lazy loading + order.getCustomer(); + + List loggedSql = LoggedSqlCollector.stop(); + Assert.assertEquals(2, loggedSql.size()); + + Assert.assertTrue(loggedSql.get(0).contains("select t0.id c0, t0.id c1 from o_order t0 where t0.id = ?")); + Assert.assertTrue(loggedSql.get(1).contains("select t0.id c0, t0.status c1,")); + } + + @Test + public void withSelectSomeIncludeLazyLoaded() { + + init(); + + OrmQueryDetail tunedDetail = new OrmQueryDetail(); + tunedDetail.select("status, customer"); + + TunedQueryInfo tunedInfo = new TunedQueryInfo(null, tunedDetail, 0); + + Query query = server.find(Order.class).setId(1); + + tunedInfo.autoFetchTune((SpiQuery)query); + + LoggedSqlCollector.start(); + + Order order = query.findUnique(); + EntityBean eb = (EntityBean)order; + EntityBeanIntercept ebi = eb._ebean_getIntercept(); + + Assert.assertFalse(ebi.isFullyLoadedBean()); + + Set loadedPropertyNames = ebi.getLoadedPropertyNames(); + Assert.assertNotNull(loadedPropertyNames); + + Assert.assertTrue(loadedPropertyNames.contains("status")); + Assert.assertTrue(loadedPropertyNames.contains("customer")); + + // no lazy loading expected here + order.getCustomer(); + + List loggedSql = LoggedSqlCollector.stop(); + Assert.assertEquals(1, loggedSql.size()); + } + + @Test + public void withSelectSome() { + + init(); + + OrmQueryDetail tunedDetail = new OrmQueryDetail(); + tunedDetail.select("status"); + + TunedQueryInfo tunedInfo = new TunedQueryInfo(null, tunedDetail, 0); + + Query query = server.find(Order.class).setId(1); + + tunedInfo.autoFetchTune((SpiQuery)query); + + LoggedSqlCollector.start(); + + Order order = query.findUnique(); + EntityBean eb = (EntityBean)order; + EntityBeanIntercept ebi = eb._ebean_getIntercept(); + + Assert.assertFalse(ebi.isFullyLoadedBean()); + + Set loadedPropertyNames = ebi.getLoadedPropertyNames(); + Assert.assertNotNull(loadedPropertyNames); + + Assert.assertTrue(loadedPropertyNames.contains("status")); + Assert.assertFalse(loadedPropertyNames.contains("customer")); + + // no lazy loading expected here + order.getCustomer(); + + List loggedSql = LoggedSqlCollector.stop(); + Assert.assertEquals(2, loggedSql.size()); + } + +} diff --git a/src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryWithNullFetchedBeanTest.java b/src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryWithNullFetchedBeanTest.java new file mode 100644 index 000000000..2e304b56b --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/autofetch/TunedQueryWithNullFetchedBeanTest.java @@ -0,0 +1,68 @@ +package com.avaje.ebeaninternal.server.autofetch; + +import java.util.List; +import java.util.Set; + +import org.avaje.ebeantest.LoggedSqlCollector; +import org.junit.Assert; +import org.junit.Test; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.EbeanServer; +import com.avaje.ebean.Query; +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebean.bean.EntityBeanIntercept; +import com.avaje.tests.model.basic.Address; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; + +public class TunedQueryWithNullFetchedBeanTest extends BaseTestCase { + + EbeanServer server = Ebean.getServer(null); + + @Test + public void withFetchOfNullBeanJoin() { + + ResetBasicData.reset(); + + Customer newCustomer = new Customer(); + newCustomer.setName("TestFetchBillingAddress"); + server.save(newCustomer); + + Query query = server.find(Customer.class) + .setId(newCustomer.getId()) + .fetch("billingAddress","id"); + + LoggedSqlCollector.start(); + + Customer customer = query.findUnique(); + EntityBean eb = (EntityBean)customer; + EntityBeanIntercept ebi = eb._ebean_getIntercept(); + + Assert.assertTrue(ebi.isFullyLoadedBean()); + + // find the internal property index for "billingAddress" + String[] propNames = eb._ebean_getPropertyNames(); + int pos = 0; + for (int i = 0; i < propNames.length; i++) { + if (propNames[i].equals("billingAddress")) { + pos = i; + } + } + + // The billing address is loaded (but value null) + Assert.assertTrue(ebi.isLoadedProperty(pos)); + + Set loadedPropertyNames = ebi.getLoadedPropertyNames(); + Assert.assertNull(loadedPropertyNames); + + // no lazy loading expected here, value is null + Address billingAddress = customer.getBillingAddress(); + Assert.assertNull(billingAddress); + + // assert only one query executed + List loggedSql = LoggedSqlCollector.stop(); + Assert.assertEquals(1, loggedSql.size()); + } +}