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 d3e5d7c44..f3f85b7d3 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 @@ -417,6 +417,7 @@ public class JDBCStoreManager oid.equals(owner.getObjectId())) { sm.storeObject(fmd[j].getIndex(), owner.getPersistenceCapable()); + break; } } } 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 590146628..cf2e26a1c 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 @@ -313,7 +313,8 @@ public abstract class StoreCollectionFieldStrategy seq = res.getInt(field.getOrderColumn(), orderJoins) + 1; // for inverse relation field - setMappedBy(oid, res); + setMappedBy(oid.equals(sm.getObjectId()) ? + sm.getPersistenceCapable() : oid, res); Object val = loadElement(null, store, fetch, res, dataJoins); add(store, coll, val); } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyEagerChild.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyEagerChild.java new file mode 100644 index 000000000..180bb39a3 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyEagerChild.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.relations; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Version; + +@Entity +public class OneManyEagerChild { + + @Id + @GeneratedValue + private long id; + + private String name; + + @ManyToOne(fetch=FetchType.EAGER) + @JoinColumn(name="PARENT_ID") + private OneManyEagerParent parent; + + @Version + private Integer optLock; + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public OneManyEagerParent getParent() { + return parent; + } + + public void setParent(OneManyEagerParent parent) { + this.parent = parent; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyEagerParent.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyEagerParent.java new file mode 100644 index 000000000..61638df7c --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyEagerParent.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.relations; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; +import javax.persistence.Version; + +@Entity +public class OneManyEagerParent { + + @Id + @GeneratedValue + private long id; + + private String name; + + @OneToMany(mappedBy="parent", fetch=FetchType.EAGER) + @OrderBy("name ASC") + private List lazychildren = + new ArrayList(); + + @OneToMany(mappedBy="parent", fetch=FetchType.EAGER) + @OrderBy("name ASC") + private List eagerchildren = + new ArrayList(); + + @Version + private Integer optLock; + + public long getId() { + return id; + } + + public List getLazyChildren() { + return lazychildren; + } + + public void addLazyChild(OneManyLazyChild child) { + child.setParent(this); + lazychildren.add(child); + } + + public List getEagerChildren() { + return eagerchildren; + } + + public void addEagerChild(OneManyEagerChild child) { + child.setParent(this); + eagerchildren.add(child); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyLazyChild.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyLazyChild.java new file mode 100644 index 000000000..4dd09e887 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/OneManyLazyChild.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.relations; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Version; + +@Entity +public class OneManyLazyChild { + + @Id + @GeneratedValue + private long id; + + private String name; + + @ManyToOne(fetch=FetchType.LAZY) + @JoinColumn(name="PARENT_ID") + private OneManyEagerParent parent; + + @Version + private Integer optLock; + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public OneManyEagerParent getParent() { + return parent; + } + + public void setParent(OneManyEagerParent parent) { + this.parent = parent; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestManyEagerSQL.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestManyEagerSQL.java new file mode 100644 index 000000000..656ff90c5 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestManyEagerSQL.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.relations; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import junit.textui.TestRunner; + +import org.apache.openjpa.persistence.OpenJPAEntityManager; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + + +public class TestManyEagerSQL + extends SQLListenerTestCase { + + public void setUp() { + setUp( + OneManyEagerParent.class, OneManyEagerChild.class, + OneManyLazyChild.class); + + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + + for (int j = 0; j < 2; j++) { + OneManyEagerParent parent = new OneManyEagerParent(); + parent.setName("parent"+j); + for (int i = 0; i < 2; i++) { + OneManyEagerChild child = new OneManyEagerChild(); + child.setName("eagerchild" + i); + parent.addEagerChild(child); + em.persist(child); + OneManyLazyChild lazychild = new OneManyLazyChild(); + lazychild.setName("lazychild" + i); + parent.addLazyChild(lazychild); + em.persist(lazychild); + } + em.persist(parent); + } + + em.flush(); + em.getTransaction().commit(); + em.close(); + } + + public void testManyToOneEagerQuery() { + sql.clear(); + + OpenJPAEntityManager em = emf.createEntityManager(); + String query = "select c FROM OneManyEagerChild c"; + Query q = em.createQuery(query); + List list = q.getResultList(); + assertEquals(4, list.size()); + + // Expected SQLs: + // SELECT t0.id, t0.optLock, t0.name, t1.id, t1.optLock, t1.name + // FROM OneManyEagerChild t0 + // LEFT OUTER JOIN OneManyEagerParent t1 ON t0.PARENT_ID = t1.id + // SELECT t0.id, t0.optLock, t0.name FROM OneManyEagerChild t0 + // WHERE t0.PARENT_ID = ? ORDER BY t0.name ASC [params=(long) 2] + // SELECT t0.id, t0.optLock, t0.name, t0.PARENT_ID + // FROM OneManyLazyChild t0 WHERE t0.PARENT_ID = ? + // ORDER BY t0.name ASC [params=(long) 2] + // SELECT t0.id, t0.optLock, t0.name FROM OneManyEagerChild t0 + // WHERE t0.PARENT_ID = ? ORDER BY t0.name ASC [params=(long) 1] + // SELECT t0.id, t0.optLock, t0.name, t0.PARENT_ID + // FROM OneManyLazyChild t0 WHERE t0.PARENT_ID = ? + // ORDER BY t0.name ASC [params=(long) 1] + + assertEquals(5, sql.size()); + + sql.clear(); + + for (int i = 0; i < list.size(); i++) { + OneManyEagerChild child = (OneManyEagerChild) list.get(i); + assertEquals(2, child.getParent().getLazyChildren().size()); + assertEquals(2, child.getParent().getEagerChildren().size()); + } + assertEquals(0, sql.size()); + + em.close(); + } + + public void testManyToOneLazyQuery() { + sql.clear(); + + OpenJPAEntityManager em = emf.createEntityManager(); + String query = "select c FROM OneManyLazyChild c"; + Query q = em.createQuery(query); + List list = q.getResultList(); + assertEquals(4, list.size()); + + // Expected SQL: + // SELECT t0.id, t0.optLock, t0.name, t0.PARENT_ID + // FROM OneManyLazyChild t0 + assertEquals(1, sql.size()); + + sql.clear(); + + for (int i = 0; i < list.size(); i++) { + OneManyLazyChild child = (OneManyLazyChild) list.get(i); + assertEquals(2, child.getParent().getLazyChildren().size()); + assertEquals(2, child.getParent().getEagerChildren().size()); + } + + // Expected SQLs: (fired on child.getParent()) + // SELECT t0.optLock, t0.name, t1.PARENT_ID, t1.id, t1.optLock, t1.name + // FROM OneManyEagerParent t0 + // LEFT OUTER JOIN OneManyEagerChild t1 ON t0.id = t1.PARENT_ID + // WHERE t0.id = ? + // ORDER BY t1.PARENT_ID ASC, t1.name ASC [params=(long) 252] + // SELECT t0.id, t0.optLock, t0.name, t0.PARENT_ID + // FROM OneManyLazyChild t0 WHERE t0.PARENT_ID = ? + // ORDER BY t0.name ASC [params=(long) 252] + // SELECT t0.optLock, t0.name, t1.PARENT_ID, t1.id, t1.optLock, t1.name + // FROM OneManyEagerParent t0 + // LEFT OUTER JOIN OneManyEagerChild t1 ON t0.id = t1.PARENT_ID + // WHERE t0.id = ? + // ORDER BY t1.PARENT_ID ASC, t1.name ASC [params=(long) 251] + // SELECT t0.id, t0.optLock, t0.name, t0.PARENT_ID + // FROM OneManyLazyChild t0 WHERE t0.PARENT_ID = ? + // ORDER BY t0.name ASC [params=(long) 251] + + assertEquals(4, sql.size()); + + em.close(); + } + + public void testOneToManyEagerQuery() { + sql.clear(); + + OpenJPAEntityManager em = emf.createEntityManager(); + String query = "select p FROM OneManyEagerParent p"; + Query q = em.createQuery(query); + List list = q.getResultList(); + assertEquals(2, list.size()); + + // Expected SQLs: + // SELECT t0.id, t0.optLock, t0.name FROM OneManyEagerParent t0 + // SELECT t0.id, t1.id, t1.optLock, t1.name FROM OneManyEagerParent t0 + // INNER JOIN OneManyEagerChild t1 ON t0.id = t1.PARENT_ID + // ORDER BY t0.id ASC, t1.name ASC + // SELECT t0.id, t1.id, t1.optLock, t1.name, t1.PARENT_ID + // FROM OneManyEagerParent t0 + // INNER JOIN OneManyLazyChild t1 ON t0.id = t1.PARENT_ID + // ORDER BY t0.id ASC, t1.name ASC + + assertEquals(3, sql.size()); + + sql.clear(); + + for (int i = 0; i < list.size(); i++) { + OneManyEagerParent p = (OneManyEagerParent) list.get(i); + long id = p.getId(); + assertEquals(2, p.getEagerChildren().size()); + assertEquals(p, p.getEagerChildren().get(0).getParent()); + assertEquals(p, p.getEagerChildren().get(1).getParent()); + assertEquals(id, p.getEagerChildren().get(0).getParent().getId()); + assertEquals(id, p.getEagerChildren().get(1).getParent().getId()); + assertEquals("eagerchild0", p.getEagerChildren().get(0).getName()); + assertEquals("eagerchild1", p.getEagerChildren().get(1).getName()); + assertEquals(2, p.getLazyChildren().size()); + assertEquals(p, p.getLazyChildren().get(0).getParent()); + assertEquals(p, p.getLazyChildren().get(1).getParent()); + assertEquals(id, p.getLazyChildren().get(0).getParent().getId()); + assertEquals(id, p.getLazyChildren().get(1).getParent().getId()); + assertEquals("lazychild0", p.getLazyChildren().get(0).getName()); + assertEquals("lazychild1", p.getLazyChildren().get(1).getName()); + } + + assertEquals(0, sql.size()); + em.close(); + } + + public static void main(String[] args) { + TestRunner.run(TestManyEagerSQL.class); + } +} +