You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by aw...@apache.org on 2007/03/27 21:24:55 UTC

svn commit: r523046 - in /incubator/openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/

Author: awhite
Date: Tue Mar 27 12:24:54 2007
New Revision: 523046

URL: http://svn.apache.org/viewvc?view=rev&rev=523046
Log:
OPENJPA-181 : Fix class cast exception by passing along the StoreQuery context
whenever we pass around an Executor, so that the StoreQuery and Executor are
always matched.


Added:
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java   (with props)
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java   (with props)
Modified:
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java?view=diff&rev=523046&r1=523045&r2=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java Tue Mar 27 12:24:54 2007
@@ -108,11 +108,11 @@
         implements Executor {
 
         public Number executeDelete(StoreQuery q, Object[] params) {
-            return q.getContext().deleteInMemory(this, params);
+            return q.getContext().deleteInMemory(q, this, params);
         }
 
         public Number executeUpdate(StoreQuery q, Object[] params) {
-            return q.getContext().updateInMemory(this, params);
+            return q.getContext().updateInMemory(q, this, params);
         }
 
         public String[] getDataStoreActions(StoreQuery q, Object[] params,

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java?view=diff&rev=523046&r1=523045&r2=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java Tue Mar 27 12:24:54 2007
@@ -403,17 +403,19 @@
         }
     }
 
-    public Number deleteInMemory(StoreQuery.Executor ex, Object[] params) {
+    public Number deleteInMemory(StoreQuery q, StoreQuery.Executor ex, 
+        Object[] params) {
         try {
-            return _query.deleteInMemory(ex, params);
+            return _query.deleteInMemory(q, ex, params);
         } catch (RuntimeException re) {
             throw translate(re);
         }
     }
 
-    public Number updateInMemory(StoreQuery.Executor ex, Object[] params) {
+    public Number updateInMemory(StoreQuery q, StoreQuery.Executor ex, 
+        Object[] params) {
         try {
-            return _query.updateInMemory(ex, params);
+            return _query.updateInMemory(q, ex, params);
         } catch (RuntimeException re) {
             throw translate(re);
         }

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java?view=diff&rev=523046&r1=523045&r2=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java Tue Mar 27 12:24:54 2007
@@ -679,7 +679,7 @@
             Number num = ((ExpressionStoreQuery) q).executeDelete(this, _meta,
                 _metas, _subs, _facts, _exps, params);
             if (num == null)
-                return q.getContext().deleteInMemory(this, params);
+                return q.getContext().deleteInMemory(q, this, params);
             return num;
         }
 
@@ -687,7 +687,7 @@
             Number num = ((ExpressionStoreQuery) q).executeUpdate(this, _meta,
                 _metas, _subs, _facts, _exps, params);
             if (num == null)
-                return q.getContext().updateInMemory(this, params);
+                return q.getContext().updateInMemory(q, this, params);
             return num;
         }
 

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java?view=diff&rev=523046&r1=523045&r2=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java Tue Mar 27 12:24:54 2007
@@ -252,13 +252,15 @@
      * Helper method to delete the objects found by executing a query on
      * the given executor.
      */
-    public Number deleteInMemory(StoreQuery.Executor ex, Object[] params);
+    public Number deleteInMemory(StoreQuery q, StoreQuery.Executor ex, 
+        Object[] params);
 
     /**
      * Helper method to update the objects found by executing a query on
      * the given executor.
      */
-    public Number updateInMemory(StoreQuery.Executor ex, Object[] params);
+    public Number updateInMemory(StoreQuery q, StoreQuery.Executor ex, 
+        Object[] params);
 
     /**
      * Helper method to instantiate the class with the given name, taking

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java?view=diff&rev=523046&r1=523045&r2=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java Tue Mar 27 12:24:54 2007
@@ -558,7 +558,7 @@
         try {
             assertOpen();
             StoreQuery.Executor ex = compileForExecutor();
-            getResultPacker(ex);
+            getResultPacker(_storeQuery, ex);
             ex.validate(_storeQuery);
         } finally {
             unlock();
@@ -782,17 +782,17 @@
                 StoreQuery.Executor ex = (isInMemory(operation))
                     ? compileForInMemory(comp) : compileForDataStore(comp);
 
-                assertParameters(ex, params);
+                assertParameters(_storeQuery, ex, params);
                 if (_log.isTraceEnabled())
                     logExecution(operation, ex.getParameterTypes(_storeQuery),
                         params);
 
                 if (operation == OP_SELECT)
-                    return execute(ex, params);
+                    return execute(_storeQuery, ex, params);
                 if (operation == OP_DELETE)
-                    return delete(ex, params);
+                    return delete(_storeQuery, ex, params);
                 if (operation == OP_UPDATE)
-                    return update(ex, params);
+                    return update(_storeQuery, ex, params);
                 throw new UnsupportedException();
             } catch (OpenJPAException ke) {
                 throw ke;
@@ -826,16 +826,16 @@
 
                 Object[] arr = (params.isEmpty()) ? StoreQuery.EMPTY_OBJECTS :
                     toParameterArray(ex.getParameterTypes(_storeQuery), params);
-                assertParameters(ex, arr);
+                assertParameters(_storeQuery, ex, arr);
                 if (_log.isTraceEnabled())
                     logExecution(operation, params);
 
                 if (operation == OP_SELECT)
-                    return execute(ex, arr);
+                    return execute(_storeQuery, ex, arr);
                 if (operation == OP_DELETE)
-                    return delete(ex, arr);
+                    return delete(_storeQuery, ex, arr);
                 if (operation == OP_UPDATE)
-                    return update(ex, arr);
+                    return update(_storeQuery, ex, arr);
                 throw new UnsupportedException();
             } catch (OpenJPAException ke) {
                 throw ke;
@@ -964,21 +964,22 @@
      * values. All other execute methods delegate to this one or to
      * {@link #execute(StoreQuery.Executor,Map)} after validation and locking.
      */
-    private Object execute(StoreQuery.Executor ex, Object[] params)
+    private Object execute(StoreQuery q, StoreQuery.Executor ex, 
+        Object[] params)
         throws Exception {
         // if this is an impossible result range, return null / empty list
         StoreQuery.Range range = new StoreQuery.Range(_startIdx, _endIdx);
         if (!_rangeSet)
-            ex.getRange(_storeQuery, params, range);
+            ex.getRange(q, params, range);
         if (range.start >= range.end)
-            return emptyResult(ex);
+            return emptyResult(q, ex);
 
         // execute; if we have a result class or we have only one result
         // and so need to remove it from its array, wrap in a packing rop
         range.lrs = isLRS(range.start, range.end);
-        ResultObjectProvider rop = ex.executeQuery(_storeQuery, params, range);
+        ResultObjectProvider rop = ex.executeQuery(q, params, range);
         try {
-            return toResult(ex, rop, range);
+            return toResult(q, ex, rop, range);
         } catch (Exception e) {
             if (rop != null)
                 try { rop.close(); } catch (Exception e2) {}
@@ -993,16 +994,16 @@
      * The return value will be a Number indicating the number of
      * instances deleted.
      */
-    private Number delete(StoreQuery.Executor ex, Object[] params)
+    private Number delete(StoreQuery q, StoreQuery.Executor ex, Object[] params)
         throws Exception {
-        assertBulkModify(ex, params);
-        return ex.executeDelete(_storeQuery, params);
+        assertBulkModify(q, ex, params);
+        return ex.executeDelete(q, params);
     }
 
-    public Number deleteInMemory(StoreQuery.Executor executor,
+    public Number deleteInMemory(StoreQuery q, StoreQuery.Executor executor,
         Object[] params) {
         try {
-            Object o = execute(executor, params);
+            Object o = execute(q, executor, params);
             if (!(o instanceof Collection))
                 o = Collections.singleton(o);
 
@@ -1024,16 +1025,16 @@
      * The return value will be a Number indicating the number of
      * instances updated.
      */
-    private Number update(StoreQuery.Executor ex, Object[] params)
+    private Number update(StoreQuery q, StoreQuery.Executor ex, Object[] params)
         throws Exception {
-        assertBulkModify(ex, params);
-        return ex.executeUpdate(_storeQuery, params);
+        assertBulkModify(q, ex, params);
+        return ex.executeUpdate(q, params);
     }
 
-    public Number updateInMemory(StoreQuery.Executor executor,
+    public Number updateInMemory(StoreQuery q, StoreQuery.Executor executor,
         Object[] params) {
         try {
-            Object o = execute(executor, params);
+            Object o = execute(q, executor, params);
             if (!(o instanceof Collection))
                 o = Collections.singleton(o);
 
@@ -1188,13 +1189,13 @@
     /**
      * Return the query result for the given result object provider.
      */
-    protected Object toResult(StoreQuery.Executor ex, ResultObjectProvider rop,
-        StoreQuery.Range range)
+    protected Object toResult(StoreQuery q, StoreQuery.Executor ex, 
+        ResultObjectProvider rop, StoreQuery.Range range)
         throws Exception {
         // pack projections if necessary
-        String[] aliases = ex.getProjectionAliases(_storeQuery);
-        if (!ex.isPacking(_storeQuery)) {
-            ResultPacker packer = getResultPacker(ex);
+        String[] aliases = ex.getProjectionAliases(q);
+        if (!ex.isPacking(q)) {
+            ResultPacker packer = getResultPacker(q, ex);
             if (packer != null || aliases.length == 1)
                 rop = new PackingResultObjectProvider(rop, packer,
                     aliases.length);
@@ -1202,15 +1203,14 @@
 
         // if single result, extract it
         if (_unique == Boolean.TRUE || (aliases.length > 0
-            && !ex.hasGrouping(_storeQuery) && ex.isAggregate(_storeQuery)))
+            && !ex.hasGrouping(q) && ex.isAggregate(q)))
             return singleResult(rop, range);
 
         // now that we've executed the query, we can call isAggregate and
         // hasGrouping efficiently
         boolean detach = (_broker.getAutoDetach() &
             AutoDetach.DETACH_NONTXREAD) > 0 && !_broker.isActive();
-        boolean lrs = range.lrs && !ex.isAggregate(_storeQuery)
-            && !ex.hasGrouping(_storeQuery);
+        boolean lrs = range.lrs && !ex.isAggregate(q) && !ex.hasGrouping(q);
         ResultList res = (!detach && lrs) ? _fc.newResultList(rop)
             : new EagerResultList(rop);
 
@@ -1228,23 +1228,23 @@
     /**
      * Return a result packer for this projection, or null.
      */
-    private ResultPacker getResultPacker(StoreQuery.Executor ex) {
+    private ResultPacker getResultPacker(StoreQuery q, StoreQuery.Executor ex) {
         if (_packer != null)
             return _packer;
 
         Class resultClass = (_resultClass != null) ? _resultClass
-            : ex.getResultClass(_storeQuery);
+            : ex.getResultClass(q);
         if (resultClass == null)
             return null;
 
-        String[] aliases = ex.getProjectionAliases(_storeQuery);
+        String[] aliases = ex.getProjectionAliases(q);
         if (aliases.length == 0) {
             // result class but no result; means candidate is being set
             // into some result class
             _packer = new ResultPacker(_class, getAlias(), resultClass);
         } else if (resultClass != null) {
             // projection
-            Class[] types = ex.getProjectionTypes(_storeQuery);
+            Class[] types = ex.getProjectionTypes(q);
             _packer = new ResultPacker(types, aliases, resultClass);
         }
         return _packer;
@@ -1253,9 +1253,9 @@
     /**
      * Create an empty result for this query.
      */
-    private Object emptyResult(StoreQuery.Executor ex) {
+    private Object emptyResult(StoreQuery q, StoreQuery.Executor ex) {
         if (_unique == Boolean.TRUE || (_unique == null
-            && !ex.hasGrouping(_storeQuery) && ex.isAggregate(_storeQuery)))
+            && !ex.hasGrouping(q) && ex.isAggregate(q)))
             return null;
         return Collections.EMPTY_LIST;
     }
@@ -1387,7 +1387,7 @@
             StoreQuery.Executor ex = compileForExecutor();
             Object[] arr = toParameterArray(ex.getParameterTypes(_storeQuery),
                 params);
-            assertParameters(ex, arr);
+            assertParameters(_storeQuery, ex, arr);
             StoreQuery.Range range = new StoreQuery.Range(_startIdx, _endIdx);
             if (!_rangeSet)
                 ex.getRange(_storeQuery, arr, range);
@@ -1636,14 +1636,15 @@
      * Check that we are in a state to be able to perform a bulk operation;
      * also flush the current modfications if any elements are currently dirty.
      */
-    private void assertBulkModify(StoreQuery.Executor ex, Object[] params) {
+    private void assertBulkModify(StoreQuery q, StoreQuery.Executor ex, 
+        Object[] params) {
         _broker.assertActiveTransaction();
         if (_startIdx != 0 || _endIdx != Long.MAX_VALUE)
             throw new UserException(_loc.get("no-modify-range"));
         if (_resultClass != null)
             throw new UserException(_loc.get("no-modify-resultclass"));
         StoreQuery.Range range = new StoreQuery.Range();
-        ex.getRange(_storeQuery, params, range);
+        ex.getRange(q, params, range);
         if (range.start != 0 || range.end != Long.MAX_VALUE)
             throw new UserException(_loc.get("no-modify-range"));
     }
@@ -1651,11 +1652,12 @@
     /**
      * Checks that the passed parameters match the declarations.
      */
-    protected void assertParameters(StoreQuery.Executor ex, Object[] params) {
-        if (!_storeQuery.requiresParameterDeclarations())
+    protected void assertParameters(StoreQuery q, StoreQuery.Executor ex, 
+        Object[] params) {
+        if (!q.requiresParameterDeclarations())
             return;
 
-        LinkedMap paramTypes = ex.getParameterTypes(_storeQuery);
+        LinkedMap paramTypes = ex.getParameterTypes(q);
         int typeCount = paramTypes.size();
         if (typeCount > params.length)
             throw new UserException(_loc.get("unbound-params",

Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java?view=auto&rev=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java Tue Mar 27 12:24:54 2007
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.datacache;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class CascadeChild {
+
+    @Id
+    @GeneratedValue
+    private long id;
+
+    private String name;
+
+    public long getId() { 
+        return id; 
+    }
+
+    public String getName() { 
+        return name; 
+    }
+
+    public void setName(String name) { 
+        this.name = name; 
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeChild.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java?view=auto&rev=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java Tue Mar 27 12:24:54 2007
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.datacache;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+
+@Entity
+public class CascadeParent {
+
+    @Id
+    @GeneratedValue
+    private long id;
+
+    private String name;
+
+    @OneToOne(cascade=CascadeType.ALL)
+    private CascadeChild child;
+
+    public long getId() { 
+        return id; 
+    }
+
+    public String getName() { 
+        return name; 
+    }
+
+    public void setName(String name) { 
+        this.name = name; 
+    }
+
+    public CascadeChild getChild() {
+        return child;
+    }
+
+    public void setChild(CascadeChild child) {
+        this.child = child;
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CascadeParent.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java?view=diff&rev=523046&r1=523045&r2=523046
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java (original)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/TestBulkJPQLAndDataCache.java Tue Mar 27 12:24:54 2007
@@ -2,6 +2,7 @@
 
 import java.util.List;
 import java.util.Map;
+import javax.persistence.EntityManager;
 
 import org.apache.openjpa.persistence.OpenJPAEntityManager;
 import org.apache.openjpa.persistence.OpenJPAPersistence;
@@ -14,7 +15,7 @@
     private Object oid;
 
     public TestBulkJPQLAndDataCache() {
-        super(AllFieldTypes.class);
+        super(AllFieldTypes.class, CascadeParent.class, CascadeChild.class);
     }
 
     @Override
@@ -43,6 +44,24 @@
         em.close();
     }
 
+    public void tearDown() 
+        throws Exception {
+        if (emf == null)
+            return;
+        try {
+            EntityManager em = emf.createEntityManager();
+            em.getTransaction().begin();
+            em.createQuery("DELETE FROM AllFieldTypes").executeUpdate();
+            em.createQuery("DELETE FROM CascadeParent").executeUpdate();
+            em.createQuery("DELETE FROM CascadeChild").executeUpdate();
+            em.getTransaction().commit();
+            em.close();
+        } catch (Exception e) {
+        }
+
+        super.tearDown();
+    }
+
     public void testBulkDelete() {
         OpenJPAEntityManager em =
             OpenJPAPersistence.cast(emf.createEntityManager());
@@ -86,6 +105,40 @@
         assertFalse(OpenJPAPersistence.cast(emf).getStoreCache()
             .contains(AllFieldTypes.class, oid));
 
+        em.close();
+    }
+
+    public void testBulkDeleteOfCascadingEntity() {
+        CascadeParent parent = new CascadeParent();
+        parent.setName("parent");
+        CascadeChild child = new CascadeChild();
+        child.setName("child");
+        parent.setChild(child);
+
+        EntityManager em = emf.createEntityManager();
+        em.getTransaction().begin();
+        em.persist(parent);
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        assertEquals(1, em.createQuery("SELECT o FROM CascadeParent o").
+            getResultList().size());
+        assertEquals(1, em.createQuery("SELECT o FROM CascadeChild o").
+            getResultList().size());
+        em.close();
+
+        em = emf.createEntityManager();
+        em.getTransaction().begin();
+        em.createQuery("DELETE FROM CascadeParent o").executeUpdate();
+        em.getTransaction().commit();
+        em.close();
+
+        em = emf.createEntityManager();
+        assertEquals(0, em.createQuery("SELECT o FROM CascadeParent o").
+            getResultList().size());
+        assertEquals(0, em.createQuery("SELECT o FROM CascadeChild o").
+            getResultList().size());
         em.close();
     }
 }