OPENJPA-744 OneToMany EAGER loading generates extra SQLs on inverse ManyToOne relation

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@703912 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Catalina Wei 2008-10-13 04:37:48 +00:00
parent 99dc9d8a66
commit 212ddcefc9
4 changed files with 101 additions and 6 deletions

View File

@ -354,7 +354,11 @@ public class JDBCStoreManager
getMappedByFieldMapping(); getMappedByFieldMapping();
Object mappedByObject = info.result.getMappedByValue(); Object mappedByObject = info.result.getMappedByValue();
if (mappedByFieldMapping != null && mappedByObject != null) 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 // load the selected mappings into the given state manager
if (res != null) { if (res != null) {
@ -914,9 +918,29 @@ public class JDBCStoreManager
ConnectionInfo info = new ConnectionInfo(); ConnectionInfo info = new ConnectionInfo();
info.result = result; info.result = result;
info.mapping = mapping; 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); 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 * Load the given state manager with data from the result set. Only
* mappings originally selected will be loaded. * mappings originally selected will be loaded.

View File

@ -312,8 +312,8 @@ public abstract class StoreCollectionFieldStrategy
if (field.getOrderColumn() != null) if (field.getOrderColumn() != null)
seq = res.getInt(field.getOrderColumn(), orderJoins) + 1; seq = res.getInt(field.getOrderColumn(), orderJoins) + 1;
// for inverseEager field // for inverse relation field
setMappedBy(oid, sm, coll, res); setMappedBy(oid, res);
Object val = loadElement(null, store, fetch, res, dataJoins); Object val = loadElement(null, store, fetch, res, dataJoins);
add(store, coll, val); add(store, coll, val);
} }
@ -322,6 +322,23 @@ public abstract class StoreCollectionFieldStrategy
return rels; 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, private void setMappedBy(Object oid, OpenJPAStateManager sm, Object coll,
Result res) { Result res) {
// for inverseEager field // for inverseEager field

View File

@ -21,6 +21,7 @@ package org.apache.openjpa.persistence.query;
import java.io.Serializable; import java.io.Serializable;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
@ -38,7 +39,7 @@ public class Publisher implements Serializable {
@Column(name="name") @Column(name="name")
private String name; private String name;
@OneToMany(mappedBy="idPublisher") @OneToMany(mappedBy="idPublisher", fetch=FetchType.EAGER)
private Set<Magazine> magazineCollection; private Set<Magazine> magazineCollection;

View File

@ -21,12 +21,16 @@ package org.apache.openjpa.persistence.relations;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.Query; import javax.persistence.Query;
import junit.textui.TestRunner; import junit.textui.TestRunner;
import org.apache.openjpa.persistence.OpenJPAEntityManager; import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAQuery; 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; import org.apache.openjpa.persistence.test.SQLListenerTestCase;
@ -36,7 +40,8 @@ public class TestInverseEagerSQL
public void setUp() { public void setUp() {
setUp(Customer.class, Customer.CustomerKey.class, Order.class, setUp(Customer.class, Customer.CustomerKey.class, Order.class,
EntityAInverseEager.class, EntityA1InverseEager.class, EntityA2InverseEager.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(); EntityManager em = emf.createEntityManager();
em.getTransaction().begin(); em.getTransaction().begin();
@ -93,7 +98,29 @@ public class TestInverseEagerSQL
c1.setD(d1); c1.setD(d1);
d1.setC(c1); 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.flush();
em.getTransaction().commit(); em.getTransaction().commit();
em.close(); em.close();
@ -197,6 +224,32 @@ public class TestInverseEagerSQL
em.close(); 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<Magazine> 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) { public static void main(String[] args) {
TestRunner.run(TestInverseEagerSQL.class); TestRunner.run(TestInverseEagerSQL.class);
} }