diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java index 7434efde5..1f28d1b71 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java @@ -354,7 +354,11 @@ public class JDBCStoreManager getMappedByFieldMapping(); Object mappedByObject = info.result.getMappedByValue(); if (mappedByFieldMapping != null && mappedByObject != null) - setMappedBy(sm, mappedByFieldMapping, mappedByObject); + if (mappedByObject instanceof OpenJPAId) + sm.setIntermediate(mappedByFieldMapping.getIndex(), + mappedByObject); + else + setMappedBy(sm, mappedByFieldMapping, mappedByObject); } // load the selected mappings into the given state manager if (res != null) { @@ -914,9 +918,29 @@ public class JDBCStoreManager ConnectionInfo info = new ConnectionInfo(); info.result = result; info.mapping = mapping; + + // if inverse relation is known, exclude loading during find + exclude = excludeInverseRelation(mapping, info, exclude); return _ctx.find(oid, fetch, exclude, info, 0); } + private BitSet excludeInverseRelation(ClassMapping mapping, + ConnectionInfo info, BitSet exclude) { + FieldMapping inverse = info.result.getMappedByFieldMapping(); + if (inverse != null) { + FieldMapping[] fms = mapping.getDefinedFieldMappings(); + if (exclude == null) + exclude = new BitSet(fms.length); + for (int i = 0; i < fms.length; i++) { + if (fms[i] == inverse) { + exclude.set(fms[i].getIndex()); + break; + } + } + } + return exclude; + } + /** * Load the given state manager with data from the result set. Only * mappings originally selected will be loaded. diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java index dc2999298..590146628 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java @@ -312,8 +312,8 @@ public abstract class StoreCollectionFieldStrategy if (field.getOrderColumn() != null) seq = res.getInt(field.getOrderColumn(), orderJoins) + 1; - // for inverseEager field - setMappedBy(oid, sm, coll, res); + // for inverse relation field + setMappedBy(oid, res); Object val = loadElement(null, store, fetch, res, dataJoins); add(store, coll, val); } @@ -322,6 +322,23 @@ public abstract class StoreCollectionFieldStrategy return rels; } + private void setMappedBy(Object oid, Result res) { + // for inverse toOne relation field + FieldMapping mappedByFieldMapping = field.getMappedByMapping(); + + if (mappedByFieldMapping != null) { + ValueMapping val = mappedByFieldMapping.getValueMapping(); + ClassMetaData decMeta = val.getTypeMetaData(); + // this inverse field does not have corresponding classMapping + // its value may be a collection/map etc. + if (decMeta == null) + return; + + res.setMappedByFieldMapping(mappedByFieldMapping); + res.setMappedByValue(oid); + } + } + private void setMappedBy(Object oid, OpenJPAStateManager sm, Object coll, Result res) { // for inverseEager field diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Publisher.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Publisher.java index 5700ba5ba..ea0f51d8f 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Publisher.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Publisher.java @@ -21,6 +21,7 @@ package org.apache.openjpa.persistence.query; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -38,7 +39,7 @@ public class Publisher implements Serializable { @Column(name="name") private String name; - @OneToMany(mappedBy="idPublisher") + @OneToMany(mappedBy="idPublisher", fetch=FetchType.EAGER) private Set magazineCollection; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java index dc71f83aa..b62245669 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java @@ -21,12 +21,16 @@ package org.apache.openjpa.persistence.relations; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Set; + import javax.persistence.EntityManager; import javax.persistence.Query; import junit.textui.TestRunner; import org.apache.openjpa.persistence.OpenJPAEntityManager; import org.apache.openjpa.persistence.OpenJPAQuery; +import org.apache.openjpa.persistence.query.Magazine; +import org.apache.openjpa.persistence.query.Publisher; import org.apache.openjpa.persistence.test.SQLListenerTestCase; @@ -36,7 +40,8 @@ public class TestInverseEagerSQL public void setUp() { setUp(Customer.class, Customer.CustomerKey.class, Order.class, EntityAInverseEager.class, EntityA1InverseEager.class, EntityA2InverseEager.class, - EntityBInverseEager.class, EntityCInverseEager.class, EntityDInverseEager.class); + EntityBInverseEager.class, EntityCInverseEager.class, EntityDInverseEager.class, + Publisher.class, Magazine.class); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); @@ -93,7 +98,29 @@ public class TestInverseEagerSQL c1.setD(d1); d1.setC(c1); } - + + Publisher p1 = new Publisher(); + p1.setName("publisher1"); + em.persist(p1); + + for (int i = 0; i < 4; i++) { + Magazine magazine = new Magazine(); + magazine.setIdPublisher(p1); + magazine.setName("magagine"+i+"_"+p1.getName()); + em.persist(magazine); + } + + Publisher p2 = new Publisher(); + p2.setName("publisher2"); + em.persist(p2); + + for (int i = 0; i < 4; i++) { + Magazine magazine = new Magazine(); + magazine.setIdPublisher(p2); + magazine.setName("magagine"+i+"_"+p2.getName()); + em.persist(magazine); + } + em.flush(); em.getTransaction().commit(); em.close(); @@ -197,6 +224,32 @@ public class TestInverseEagerSQL em.close(); } + public void testOneToManyEagerInverseLazyQuery() { + sql.clear(); + + OpenJPAEntityManager em = emf.createEntityManager(); + String query = "select p FROM Publisher p"; + Query q = em.createQuery(query); + List list = q.getResultList(); + assertEquals(2, list.size()); + assertEquals(2, sql.size()); + + sql.clear(); + for (int i = 0; i < list.size(); i++) { + Publisher p = (Publisher) list.get(i); + Set magazines = p.getMagazineCollection(); + assertEquals(4, magazines.size()); + for (Iterator iter = magazines.iterator(); iter.hasNext();) { + Magazine m = (Magazine) iter.next(); + Publisher mp = m.getIdPublisher(); + assertEquals(p, mp); + } + } + + assertEquals(0, sql.size()); + em.close(); + } + public static void main(String[] args) { TestRunner.run(TestInverseEagerSQL.class); }