diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Department.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Department.java new file mode 100644 index 000000000..07ae0f478 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Department.java @@ -0,0 +1,103 @@ +/* + * 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.jpql.joins; + +import java.io.Serializable; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Version; + +/** + * Entity implementation class for Entity: Parent + * + */ +@Entity +@Table(name="FETCHDEPT") +public class Department implements Serializable { + + private static final long serialVersionUID = -5537435298484817651L; + + @Id + private int deptno; + @Version + private int version; + private String name; + @OneToMany(cascade=CascadeType.ALL) + private List employees; + @OneToMany(cascade=CascadeType.ALL) + private List employee2s; + + public Department() { + super(); + } + + public Department(int deptno, String name) { + super(); + this.deptno = deptno; + this.name = name; + } + public int getDeptno() { + return this.deptno; + } + + public void setDeptno(int deptno) { + this.deptno = deptno; + } + + public int getVersion() { + return this.version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public List getEmployees() { + return this.employees; + } + public void setEmployees(List employees) { + this.employees = employees; + } + + public List getEmployee2s() { + return this.employee2s; + } + public void setEmployee2s(List employees) { + this.employee2s = employees; + } + + public String toString() { + return "[Department:depno=" + deptno + ", version=" + version + ", name=" + name + + ", employees=" + employees + ", employee2s=" + employee2s+ ']'; + } + +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Department_.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Department_.java new file mode 100644 index 000000000..2e80f3404 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Department_.java @@ -0,0 +1,36 @@ +/* + * 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.jpql.joins; + +import java.lang.Integer; +import java.lang.String; +import javax.persistence.metamodel.ListAttribute; +import javax.persistence.metamodel.SingularAttribute; + +@javax.persistence.metamodel.StaticMetamodel +(value=org.apache.openjpa.persistence.jpql.joins.Department.class) +@javax.annotation.Generated +(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Sat May 17 17:25:13 CDT 2014") +public class Department_ { + public static volatile SingularAttribute deptno; + public static volatile ListAttribute employee2s; + public static volatile ListAttribute employees; + public static volatile SingularAttribute name; + public static volatile SingularAttribute version; +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Employee.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Employee.java new file mode 100644 index 000000000..659b1ffc5 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Employee.java @@ -0,0 +1,78 @@ +/* + * 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.jpql.joins; + +import java.io.Serializable; +import java.lang.String; +import javax.persistence.*; + +/** + * Entity implementation class for Entity: Child + * + */ +@Entity +@Table(name="FETCHEMPL") +public class Employee implements Serializable { + + private static final long serialVersionUID = -5155314943010802723L; + + @Id + private int empno; + private String name; + @Version + private int version; + + public Employee() { + super(); + } + + public Employee(int empno, String name) { + super(); + this.empno = empno; + this.name = name; + } + + public int getEmpno() { + return this.empno; + } + + public void setEmpno(int empno) { + this.empno = empno; + } + + public int getVersion() { + return this.version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String toString() { + return "[Employee:id=" + empno + ", version=" + version + ", name=" + name + ']'; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Employee_.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Employee_.java new file mode 100644 index 000000000..2949dc4f3 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/Employee_.java @@ -0,0 +1,33 @@ +/* + * 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.jpql.joins; + +import java.lang.Integer; +import java.lang.String; +import javax.persistence.metamodel.SingularAttribute; + +@javax.persistence.metamodel.StaticMetamodel +(value=org.apache.openjpa.persistence.jpql.joins.Employee.class) +@javax.annotation.Generated +(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Sat May 17 17:25:28 CDT 2014") +public class Employee_ { + public static volatile SingularAttribute empno; + public static volatile SingularAttribute name; + public static volatile SingularAttribute version; +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/TestJoinFetchWithQueryDataCache.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/TestJoinFetchWithQueryDataCache.java new file mode 100644 index 000000000..4dc56bdd0 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/joins/TestJoinFetchWithQueryDataCache.java @@ -0,0 +1,224 @@ +/* + * 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.jpql.joins; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.Root; + +import junit.framework.Assert; + +import org.apache.openjpa.persistence.test.SingleEMFTestCase; + +/** + * Tests JQPL and Criteria API equivalent using left join fetch with QueryCache and DataCache enabled. + */ +public class TestJoinFetchWithQueryDataCache extends SingleEMFTestCase { + EntityManager em; + public void setUp() { + super.setUp(DROP_TABLES, Employee.class, Department.class + , "openjpa.QueryCompilationCache", "all" + , "openjpa.DataCache", "true(CacheSize=2000, SoftReferenceSize=0, EvictionSchedule='+60' )" + , "openjpa.RemoteCommitProvider", "sjvm" + , "openjpa.QueryCache", "true" + ); + + em = emf.createEntityManager(); + em.getTransaction().begin(); + + Department dept; + dept = new Department(10, "department 10"); + dept.setEmployees(new ArrayList()); + dept.getEmployees().add(new Employee(11, "Emp11")); + dept.getEmployees().add(new Employee(12, "Emp12")); + dept.setEmployee2s(new ArrayList()); + dept.getEmployee2s().add(new Employee(211, "Emp211")); + dept.getEmployee2s().add(new Employee(212, "Emp212")); + em.persist(dept); + + dept = new Department(20, "department 20"); + dept.setEmployees(new ArrayList()); + dept.getEmployees().add(new Employee(21, "Emp21")); + dept.getEmployees().add(new Employee(22, "Emp22")); + dept.setEmployee2s(new ArrayList()); + dept.getEmployee2s().add(new Employee(221, "Emp221")); + dept.getEmployee2s().add(new Employee(222, "Emp222")); + em.persist(dept); + + em.getTransaction().commit(); + + em.close(); + } + + public void testJPQLNoFetch() { + EntityManager em = emf.createEntityManager(); + List ds = em.createQuery( + "SELECT DISTINCT d FROM Department d WHERE d.deptno = 10") + .getResultList(); + System.out.println("-- testJPQLNoFetch -----"); + em.clear(); + Assert.assertEquals(1, ds.size()); + for (Department x : ds) { + Assert.assertNull(x.getEmployees()); + Assert.assertNull(x.getEmployee2s()); + System.out.println(x); + } + + em.close(); + } + + public void testJPQLOneFetch() { + EntityManager em = emf.createEntityManager(); + List ds = em.createQuery( + "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.employee2s " + + "WHERE d.deptno = 10") + .getResultList(); + System.out.println("-- testJPQLOneFetch -----"); + em.clear(); + Assert.assertEquals(1, ds.size()); + for (Department x : ds) { + Assert.assertNull(x.getEmployees()); + Assert.assertNotNull(x.getEmployee2s()); + Assert.assertEquals(2, x.getEmployee2s().size()); + System.out.println(x); + } + + em.close(); + } + + public void testJPQLTwoFetch() { + EntityManager em = emf.createEntityManager(); + List ds = em.createQuery( + "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.employees " + + "LEFT JOIN FETCH d.employee2s " + + "WHERE d.deptno = 10") + .getResultList(); + System.out.println("-- testJPQLTwoFetch -----"); + em.clear(); + Assert.assertEquals(1, ds.size()); + for (Department x : ds) { + Assert.assertNotNull(x.getEmployees()); + Assert.assertEquals(2, x.getEmployees().size()); + Assert.assertNotNull(x.getEmployee2s()); + Assert.assertEquals(2, x.getEmployee2s().size()); + System.out.println(x); + } + + em.close(); + } + + public void testCriteriaAPINoFetch() { + EntityManager em = emf.createEntityManager(); + CriteriaBuilder cb = em.getCriteriaBuilder(); + + // This query is equivalent to the following Java Persistence query + // language query: + // SELECT d + // FROM Department d + // WHERE d.deptno = 1 + + CriteriaQuery q = cb.createQuery(Department.class); + Root d = q.from(Department.class); + q.where(cb.equal(d.get(Department_.deptno), 20)).select(d); + + List ds = em.createQuery(q).getResultList(); + System.out.println("-- testCriteriaAPINoFetch -----"); + em.clear(); + Assert.assertEquals(1, ds.size()); + for (Department x : ds) { + Assert.assertNull(x.getEmployees()); + Assert.assertNull(x.getEmployee2s()); + System.out.println(x); + } + + em.close(); + } + + public void testCriteriaAPIOneFetch() { + EntityManager em = emf.createEntityManager(); + CriteriaBuilder cb = em.getCriteriaBuilder(); + + // 6.5.4 Fetch Joins + // Example: + // CriteriaQuery q = cb.createQuery(Department.class); + // Root d = q.from(Department.class); + // d.fetch(Department_.employees, JoinType.LEFT); + // q.where(cb.equal(d.get(Department_.deptno), 1)).select(d); + // + // This query is equivalent to the following Java Persistence query + // language query: + // SELECT DISTINCT d + // FROM Department d LEFT JOIN FETCH d.employees + // WHERE d.deptno = 1 + + CriteriaQuery q = cb.createQuery(Department.class); + Root d = q.from(Department.class); + d.fetch(Department_.employees, JoinType.LEFT); + q.where(cb.equal(d.get(Department_.deptno), 20)).select(d).distinct(true); + + List ds = em.createQuery(q).getResultList(); + System.out.println("-- testCriteriaAPIOneFetch -----"); + em.clear(); + Assert.assertEquals(1, ds.size()); + for (Department x : ds) { + Assert.assertNotNull(x.getEmployees()); + Assert.assertEquals(2, x.getEmployees().size()); + Assert.assertNull(x.getEmployee2s()); + System.out.println(x); + } + + em.close(); + } + + public void testCriteriaAPITwoFetch() { + EntityManager em = emf.createEntityManager(); + CriteriaBuilder cb = em.getCriteriaBuilder(); + + // This query is equivalent to the following Java Persistence query + // language query: + // SELECT DISTINCT d + // FROM Department d LEFT JOIN FETCH d.employees LEFT JOIN FETCH d.employee2s + // WHERE d.deptno = 1 + CriteriaQuery q = cb.createQuery(Department.class); + Root d = q.from(Department.class); + d.fetch(Department_.employees, JoinType.LEFT); + d.fetch(Department_.employee2s, JoinType.LEFT); + q.where(cb.equal(d.get(Department_.deptno), 20)).select(d).distinct(true); + + List ds = em.createQuery(q).getResultList(); + System.out.println("-- testCriteriaAPITwoFetch -----"); + em.clear(); + Assert.assertEquals(1, ds.size()); + for (Department x : ds) { + Assert.assertNotNull(x.getEmployees()); + Assert.assertEquals(2, x.getEmployees().size()); + Assert.assertNotNull(x.getEmployee2s()); + Assert.assertEquals(2, x.getEmployee2s().size()); + System.out.println(x); + } + + em.close(); + } + +} diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java index b4e250460..6d84adad2 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java @@ -98,10 +98,9 @@ class CriteriaExpressionBuilder { metas.add(meta); } } - for (Fetch fetch : root.getFetches()) { - metas.add(metamodel.getRepository().getCachedMetaData(fetch.getAttribute().getJavaType())); - } } + // TODO -- need to handle subqueries + exps.accessPath = metas.toArray(new ClassMetaData[metas.size()]); }