You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by fa...@apache.org on 2010/07/22 23:54:41 UTC

svn commit: r966870 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/ openjpa-persistence-jdbc/src/test/resources/META-INF/

Author: fancy
Date: Thu Jul 22 21:54:40 2010
New Revision: 966870

URL: http://svn.apache.org/viewvc?rev=966870&view=rev
Log:
OPENJPA-1738: Prepared query does not handle collection-valued parameter of persistence-capable objects

Added:
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Child.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Parent.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/ParentId.java
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java?rev=966870&r1=966869&r2=966870&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedQueryImpl.java Thu Jul 22 21:54:40 2010
@@ -331,7 +331,7 @@ public class PreparedQueryImpl implement
                 setPersistenceCapableParameter(result, val, indices, broker);
             } else if (val instanceof Collection) {
                 setCollectionValuedParameter(result, (Collection)val, indices, 
-                    key);
+                    key, broker);
             } else {
                 for (int j : indices) {
                     if (val instanceof Enum) {
@@ -386,7 +386,7 @@ public class PreparedQueryImpl implement
     }
     
     private void setCollectionValuedParameter(Map<Integer,Object> result, 
-        Collection values, int[] indices, Object param) {
+        Collection values, int[] indices, Object param, Broker broker) {
         int n = values.size();
         Object[] array = values.toArray();
         if (n > indices.length || indices.length%n != 0) {
@@ -395,7 +395,11 @@ public class PreparedQueryImpl implement
         }
         int k = 0;
         for (int j : indices) {
-            result.put(j, array[k%n]);
+            Object val = array[k%n];
+            if (ImplHelper.isManageable(val))
+                setPersistenceCapableParameter(result, val, indices, broker);
+            else
+                result.put(j, val);
             k++;
         }
         

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Child.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Child.java?rev=966870&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Child.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Child.java Thu Jul 22 21:54:40 2010
@@ -0,0 +1,73 @@
+/*
+ * 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.jdbc.sqlcache;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+/**
+ * Child in a bidirectional parent-child relationship.
+ * 
+ * Notes:
+ * a) there is no mutator for id because it is generated by JPA provider.
+ * 
+ */
+@Entity
+@Table(name="zchild")
+public class Child {
+	@Id
+	@GeneratedValue
+	private String id;
+	
+	private String name;
+
+	@ManyToOne(fetch=FetchType.LAZY)
+	private Parent parent;
+
+	/**
+	 * Restrict access to constructor for Parent to create the Child.
+	 */
+	public Child() {
+		
+	}
+	
+	public String getId() {
+		return id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String city) {
+		this.name = city;
+	}
+
+	public Parent getParent() {
+		return parent;
+	}
+
+	void setParent(Parent owner) {
+		this.parent = owner;
+	}
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Parent.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Parent.java?rev=966870&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Parent.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/Parent.java Thu Jul 22 21:54:40 2010
@@ -0,0 +1,119 @@
+/*
+ * 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.jdbc.sqlcache;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+/**
+ * Parent in a bidirectional parent-child relationship.
+ * 
+ * Note:
+ * a) there is no mutator for id because it is generated by JPA provider.
+ * 
+ */
+@Entity
+@IdClass(ParentId.class)
+@Table(name="zparent")
+public class Parent {
+	@Id
+	private long id;
+	@Id
+	private String name;
+    @Id
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name="addrid")
+    private Address addrId;
+	
+	/**
+     * This field is mapped by the child. The child's table will hold a foreign
+     * key linking to the primary key of this Parent's table. In JPA
+     * terminology, that makes the Child the owner of this bi-directional
+     * relationship.
+	 */
+	@OneToMany(mappedBy="parent", cascade = CascadeType.ALL)
+	private Collection<Child> children;
+
+
+    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 void setAddrId(Address addr) {
+        this.addrId = addr;
+    }
+
+    public Address getAddrId() {
+        return addrId;
+    }
+
+    public Collection<Child> getChildren() {
+		return children;
+	}
+
+	/**
+     * Creates and adds a child to this receiver. Creating child via the parent
+     * is the preferred pattern to ensure referential integrity of domain model.
+	 */
+	public Child newChild(String name) {
+		Child child = new Child();
+		child.setName(name);
+		child.setParent(this);
+		if (children == null)
+			children = new ArrayList<Child>();
+		children.add(child);
+		return child;
+	}
+	
+	public boolean removeChild(Child child) {
+		return children != null && children.remove(child);
+	}
+	
+	/**
+     * Unsafe way of adding a child. Does not warranty referential integrity.
+     * The caller has to ensure bi-directionality of parent-child relation is 
+	 * consistent.
+	 */
+	public void add(Child child) {
+		if (children == null)
+			children = new ArrayList<Child>();
+		children.add(child);
+	}
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/ParentId.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/ParentId.java?rev=966870&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/ParentId.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/ParentId.java Thu Jul 22 21:54:40 2010
@@ -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.jdbc.sqlcache;
+
+public class ParentId implements java.io.Serializable {
+    private static final long serialVersionUID = 4262907482129342511L;
+    
+    private long id;
+    private String name;
+    private long addrId;
+    
+    private Integer hashcode = null;
+    
+    public ParentId() {        
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setiId(long id) {
+        this.id = id;
+    }
+    
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public long getAddrId() {
+        return addrId;
+    }
+
+    public void setAddrId(long addrId) {
+        this.addrId = addrId;
+    }
+
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+            
+        if (o instanceof ParentId) {
+            ParentId oId = (ParentId) o;
+            if (    oId.id == this.id && 
+                    oId.name.equals(this.name) &&
+                    oId.addrId == this.addrId) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    public int hashCode() {
+        if (hashcode == null) {
+            String hashStr = this.id + ":" + this.name + ":" + this.addrId;
+            hashcode = hashStr.hashCode();
+        }
+        return hashcode.intValue();
+    }
+    
+}

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java?rev=966870&r1=966869&r2=966870&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestPreparedQueryCache.java Thu Jul 22 21:54:40 2010
@@ -204,7 +204,23 @@ public class TestPreparedQueryCache exte
         em.persist(o1);
         em.persist(o2);
         
-        
+        for (int i = 1; i < 10; i++) {
+            Parent parent = new Parent();
+            parent.setId(i);
+            parent.setName(new String("Parent "+i));
+            Address addr = new Address();
+            addr.setCity("Address "+i+i);
+            parent.setAddrId(addr);
+            em.persist(addr);
+            for (int j = 1; j < 5; j++) {
+                Child child = new Child();
+                child.setName("Child "+i+j);
+                child.setParent(parent);
+                parent.add(child);
+            }
+            em.persist(parent);
+        }
+
         em.getTransaction().commit();
 	}
 
@@ -213,6 +229,80 @@ public class TestPreparedQueryCache exte
 	        em.close();
 		super.tearDown();
 	}
+
+    public void testCollectionValuedParameterOfEntities() {
+        OpenJPAEntityManager em = emf.createEntityManager();
+        String jpql1 = "select d from Department d where d.name in ('Marketing', 'Sales') order by d.name";
+        String jpql2 = "select d from Department d where d.name in ('Engineering', 'Marketing') order by d.name";
+        
+        List<Department> param1 = (List<Department>) em.createQuery(jpql1).getResultList();
+        List<Department> param2 = (List<Department>) em.createQuery(jpql2).getResultList();
+        em.clear();
+        
+        String jpql = "select e from Employee e where e.department in :param";
+        
+        List<Employee> rs1 = em.createQuery(jpql).setParameter("param", param1).getResultList();
+
+        for (int i = 0; i < rs1.size(); i++) {
+            Employee e = (Employee) rs1.get(i);
+            assertFalse(e.getDepartment().getName().equals("Engineering"));
+        }
+        
+        List<Employee> rs2 = (List<Employee>) em.createQuery(jpql).setParameter("param", param2).getResultList();
+        for (int i = 0; i < rs2.size(); i++) {
+            Employee e = (Employee) rs2.get(i);
+            assertFalse(e.getDepartment().getName().equals("Sales"));
+        }
+
+        em.clear();
+        String jpql3 = "select e from Employee e where e.department in (:p1, :p2, :p3)";
+        Query query = em.createQuery(jpql3);
+        query.setParameter("p1", param1.get(0));
+        query.setParameter("p2", param1.get(1));
+        query.setParameter("p3", param1.get(2));
+        List<Employee> rs3 = query.getResultList();
+        for (int i = 0; i < rs3.size(); i++) {
+            Employee e = (Employee) rs3.get(i);
+            assertTrue(e.getDepartment().getName().equals("Marketing"));
+        }
+
+        em.clear();
+        query = em.createQuery(jpql3);
+        query.setParameter("p1", param2.get(0));
+        query.setParameter("p2", param2.get(1));
+        query.setParameter("p3", param2.get(2));
+        List<Employee> rs4 = query.getResultList();
+        for (int i = 0; i < rs4.size(); i++) {
+            Employee e = (Employee) rs4.get(i);
+            assertTrue(e.getDepartment().getName().equals("Engineering"));
+        }
+
+        em.clear();
+        String jpql4 = "select p from Parent p where p.id < 3";
+        String jpql5 = "select p from Parent p where p.id > 6";
+        List<Parent> parm1 = em.createQuery(jpql4).getResultList();
+        List<Parent> parm2 = em.createQuery(jpql5).getResultList();
+        
+        em.clear();
+        String jpql6 = "select c from Child c where c.parent in ?1";
+        Query qry = em.createQuery(jpql6);
+        qry.setParameter(1, parm1);
+        List<Child> c1 = qry.getResultList();
+        for (int i = 0; i < c1.size(); i++) {
+            Child child = (Child) c1.get(i);
+            assertTrue(child.getParent().getId() < 3);
+        }
+        
+        em.clear();
+        qry = em.createQuery(jpql6);
+        qry.setParameter(1, parm2);
+        List<Child> c2 = qry.getResultList();
+        for (int i = 0; i < c2.size(); i++) {
+            Child child = (Child) c2.get(i);
+            assertTrue(child.getParent().getId() > 6);
+        }
+        
+    }
     
     public void testRepeatedParameterInSubqueryInDifferentOrderSubQLast() {
         OpenJPAEntityManager em = emf.createEntityManager();

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml?rev=966870&r1=966869&r2=966870&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml Thu Jul 22 21:54:40 2010
@@ -208,6 +208,8 @@
 		<class>org.apache.openjpa.persistence.jdbc.sqlcache.Person</class>
 		<class>org.apache.openjpa.persistence.jdbc.sqlcache.Singer</class>
         <class>org.apache.openjpa.persistence.jdbc.sqlcache.OrderJPA</class>
+        <class>org.apache.openjpa.persistence.jdbc.sqlcache.Parent</class>
+        <class>org.apache.openjpa.persistence.jdbc.sqlcache.Child</class>
 		
 		<properties>
 		  <property name="openjpa.jdbc.QuerySQLCache"