From 488b856470b5581d3793f006b34e70a45d71c9cb Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sun, 23 Jun 2013 15:19:46 +1200 Subject: [PATCH] Merge fix from Peter Fu, avaje-ebeanorm/pull/9 request plus associated test --- .../server/query/SqlTreeNodeBean.java | 58 ++++++++++++++++- .../tests/model/selfref/SelfRefCustomer.java | 46 ++++++++++++++ .../model/selfref/TestTextJsonSelfRef.java | 62 +++++++++++++++++++ 3 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/avaje/tests/model/selfref/SelfRefCustomer.java create mode 100644 src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.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 97f207ef5..a371f35b5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -55,7 +55,7 @@ public class SqlTreeNodeBean implements SqlTreeNode { /** * The hash of the partialProps (calculate once). */ - final int partialHash; + int partialHash; final BeanProperty[] properties; @@ -79,7 +79,7 @@ public class SqlTreeNodeBean implements SqlTreeNode { final String prefix; - final Set includedProps; + Set includedProps; final Map pathMap; @@ -230,7 +230,7 @@ public class SqlTreeNodeBean implements SqlTreeNode { contextBean = localBean; } else { // bean already exists in persistenceContext - if (queryMode.isLoadContextBean()) { + if (isLoadContextBeanNeeded(queryMode, contextBean)){ // refresh it anyway (lazy loading for example) localBean = contextBean; if (localBean instanceof EntityBean) { @@ -510,4 +510,56 @@ public class SqlTreeNodeBean implements SqlTreeNode { public String toString() { return "SqlTreeNodeBean: " + desc; } + + private boolean isLoadContextBeanNeeded(Mode queryMode, Object contextBean) { + // if explicitly set loadContextBean to true, then reload + if (queryMode.isLoadContextBean()) { + return true; + } + + // if contextBean is not EntityBean (I doubt this will happen), then reload + if (!(contextBean instanceof EntityBean)) { + return true; + } + + EntityBean cb = (EntityBean) contextBean; + + // always reload if contextBean is reference + if (cb._ebean_getIntercept().isReference()) { + return true; + } + + // when localBean is partial object + if (partialObject) { + // don't reload if localBean is partial object but contextBean is not + if (cb._ebean_intercept().getLoadedProps() == null) { + return false; + } + + // when both localBean and contextBean are partial objects + if (cb._ebean_getIntercept().getLoadedProps().containsAll(partialProps)) { + // don't reload if contextBean has all the properties which are included + // for localBean + return false; + } else { + // otherwise reload, need to add the loadedProps of context bean to the + // incluededProps of localBean + partialProps.addAll(cb._ebean_getIntercept().getLoadedProps()); + // recalculate partialHash and includedProps + partialHash = partialProps.hashCode(); + includedProps = LoadedPropertiesCache.get(partialHash, partialProps, desc); + return true; + } + } + + // when localBean is not partial object + if (cb._ebean_getIntercept().getLoadedProps() != null) { + // reload if contextBean is partial object + return true; + } + + // return false by default + return false; + } + } diff --git a/src/test/java/com/avaje/tests/model/selfref/SelfRefCustomer.java b/src/test/java/com/avaje/tests/model/selfref/SelfRefCustomer.java new file mode 100644 index 000000000..f949669b6 --- /dev/null +++ b/src/test/java/com/avaje/tests/model/selfref/SelfRefCustomer.java @@ -0,0 +1,46 @@ +package com.avaje.tests.model.selfref; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +@Entity +@Table(name = "self_ref_customer") +public class SelfRefCustomer { + + @Id + Long id; + + String name; + + @ManyToOne + @JoinColumn(name = "referred_by_id") + SelfRefCustomer referredBy; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SelfRefCustomer getReferredBy() { + return referredBy; + } + + public void setReferredBy(SelfRefCustomer referredBy) { + this.referredBy = referredBy; + } + +} \ No newline at end of file diff --git a/src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.java b/src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.java new file mode 100644 index 000000000..b7aca27da --- /dev/null +++ b/src/test/java/com/avaje/tests/model/selfref/TestTextJsonSelfRef.java @@ -0,0 +1,62 @@ +package com.avaje.tests.model.selfref; + +import java.util.List; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.BeanState; +import com.avaje.ebean.Ebean; +import com.avaje.ebean.TxRunnable; +import com.avaje.ebean.text.json.JsonWriteOptions; +import com.avaje.tests.model.selfref.SelfRefCustomer; + +public class TestTextJsonSelfRef extends BaseTestCase { + + @Test + public void test() { + + Ebean.execute(new TxRunnable() { + public void run() { + + if (Ebean.find(SelfRefCustomer.class).findRowCount() == 0) { + SelfRefCustomer c1 = new SelfRefCustomer(); + c1.setName("Foo"); + c1.setReferredBy(c1); + + SelfRefCustomer c2 = new SelfRefCustomer(); + c2.setName("Bar"); + c2.setReferredBy(c1); + + SelfRefCustomer c3 = new SelfRefCustomer(); + c3.setName("baz"); + c3.setReferredBy(c1); + + Ebean.save(c1); + Ebean.save(c2); + Ebean.save(c3); + } + } + }); + + List customers = Ebean.find(SelfRefCustomer.class).orderBy("id desc").findList(); + + // Check that there are no 'reference' beans here + for (SelfRefCustomer cust: customers) { + BeanState beanState = Ebean.getBeanState(cust); + Assert.assertFalse(beanState.isReference()); + } + +// JsonWriteOptions options = JsonWriteOptions.parsePath("(id,name,referredBy(id))"); +// String customerContent = Ebean.createJsonContext().toJsonString(customers);//, false, options); +// System.out.println("Customers: " + customerContent); +// +// Assert +// .assertEquals( +// "[{\"id\":3,\"name\":\"baz\",\"referredBy\":{\"id\":1}},{\"id\":2,\"name\":\"Bar\",\"referredBy\":{\"id\":1}},{\"id\":1,\"name\":\"Foo\",\"referredBy\":{\"id\":1}}]", +// customerContent); + } + +} \ No newline at end of file