Return-Path: Delivered-To: apmail-incubator-open-jpa-dev-archive@locus.apache.org Received: (qmail 14101 invoked from network); 26 Mar 2007 15:35:54 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 26 Mar 2007 15:35:54 -0000 Received: (qmail 86205 invoked by uid 500); 26 Mar 2007 15:36:01 -0000 Delivered-To: apmail-incubator-open-jpa-dev-archive@incubator.apache.org Received: (qmail 86089 invoked by uid 500); 26 Mar 2007 15:36:01 -0000 Mailing-List: contact open-jpa-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: open-jpa-dev@incubator.apache.org Delivered-To: mailing list open-jpa-dev@incubator.apache.org Received: (qmail 85942 invoked by uid 99); 26 Mar 2007 15:36:00 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 26 Mar 2007 08:36:00 -0700 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO brutus.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 26 Mar 2007 08:35:52 -0700 Received: from brutus (localhost [127.0.0.1]) by brutus.apache.org (Postfix) with ESMTP id 2F9C371403F for ; Mon, 26 Mar 2007 08:35:32 -0700 (PDT) Message-ID: <6494878.1174923332162.JavaMail.jira@brutus> Date: Mon, 26 Mar 2007 08:35:32 -0700 (PDT) From: "Jonathan Feinberg (JIRA)" To: open-jpa-dev@incubator.apache.org Subject: [jira] Updated: (OPENJPA-181) ClassCastException when executing bulk delete on an entity that owns a OneToOne with a Cascade.DELETE when DataCache is on In-Reply-To: <13936586.1174922852150.JavaMail.jira@brutus> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked by ClamAV on apache.org [ https://issues.apache.org/jira/browse/OPENJPA-181?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Jonathan Feinberg updated OPENJPA-181: -------------------------------------- Description: Given an entity class A which owns a OneToOne entity of class B, and given a cascade on that OneToOne that includes DELETE, an attempt to bulk-delete A when using the DataCache results in a stack trace like the following: {code} java.lang.ClassCastException: org.apache.openjpa.datacache.QueryCacheStoreQuery cannot be cast to org.apache.openjpa.kernel.ExpressionStoreQuery at org.apache.openjpa.kernel.ExpressionStoreQuery$DataStoreExecutor.executeQuery(ExpressionStoreQuery.java:674) at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:979) at org.apache.openjpa.kernel.QueryImpl.deleteInMemory(QueryImpl.java:1005) ... 28 more {code} The proximate cause for the bug is that when the JDBCStoreQuery does this: private Table getTable(FieldMapping fm, Table table) { if (fm.getCascadeDelete() != ValueMetaData.CASCADE_NONE) return INVALID; it causes "isSingleTableMapping" to be considered false, which in turn permits executeBulkOperation to return null. Meanwhile, back in DataStoreExecutor: public Number executeDelete(StoreQuery q, Object[] params) { Number num = ((ExpressionStoreQuery) q).executeDelete(this, _meta, _metas, _subs, _facts, _exps, params); if (num == null) return q.getContext().deleteInMemory(this, params); // <- now we have come here because executeDelete punted return num; } So deleteInMemory gets called in QueryImpl: public Number deleteInMemory(StoreQuery.Executor executor, Object[] params) { try { Object o = execute(executor, params); , but a DataStoreExecutor doesn't know how to execute the QueryCacheStoreQuery that it gets. Somehwere, something is too unwrapped, or not wrapped enough. Good luck! Workaround: If A owns B, then instead of cascade=CascadeType.ALL, you can @Entity class A { B myThing; @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }) B getMyThing() { return myThing; } } @Entity class B { A owner; @ForeignKey(deleteAction=ForeignKeyAction.CASCADE) A getOwner() { return owner; } } was: Given an entity class A which owns a OneToOne entity of class B, and given a cascade on that OneToOne that includes DELETE, an attempt to bulk-delete A when using the DataCache results in a stack trace like the following: java.lang.ClassCastException: org.apache.openjpa.datacache.QueryCacheStoreQuery cannot be cast to org.apache.openjpa.kernel.ExpressionStoreQuery at org.apache.openjpa.kernel.ExpressionStoreQuery$DataStoreExecutor.executeQuery(ExpressionStoreQuery.java:674) at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:979) at org.apache.openjpa.kernel.QueryImpl.deleteInMemory(QueryImpl.java:1005) ... 28 more The proximate cause for the bug is that when the JDBCStoreQuery does this: private Table getTable(FieldMapping fm, Table table) { if (fm.getCascadeDelete() != ValueMetaData.CASCADE_NONE) return INVALID; it causes "isSingleTableMapping" to be considered false, which in turn permits executeBulkOperation to return null. Meanwhile, back in DataStoreExecutor: public Number executeDelete(StoreQuery q, Object[] params) { Number num = ((ExpressionStoreQuery) q).executeDelete(this, _meta, _metas, _subs, _facts, _exps, params); if (num == null) return q.getContext().deleteInMemory(this, params); // <- now we have come here because executeDelete punted return num; } So deleteInMemory gets called in QueryImpl: public Number deleteInMemory(StoreQuery.Executor executor, Object[] params) { try { Object o = execute(executor, params); , but a DataStoreExecutor doesn't know how to execute the QueryCacheStoreQuery that it gets. Somehwere, something is too unwrapped, or not wrapped enough. Good luck! Workaround: If A owns B, then instead of cascade=CascadeType.ALL, you can @Entity class A { B myThing; @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }) B getMyThing() { return myThing; } } @Entity class B { A owner; @ForeignKey(deleteAction=ForeignKeyAction.CASCADE) A getOwner() { return owner; } } > ClassCastException when executing bulk delete on an entity that owns a OneToOne with a Cascade.DELETE when DataCache is on > -------------------------------------------------------------------------------------------------------------------------- > > Key: OPENJPA-181 > URL: https://issues.apache.org/jira/browse/OPENJPA-181 > Project: OpenJPA > Issue Type: Bug > Components: kernel > Affects Versions: 0.9.7 > Reporter: Jonathan Feinberg > > Given an entity class A which owns a OneToOne entity of class B, and given a cascade on that OneToOne that includes DELETE, an attempt to bulk-delete A when using the DataCache results in a stack trace like the following: > {code} > java.lang.ClassCastException: org.apache.openjpa.datacache.QueryCacheStoreQuery cannot be cast to org.apache.openjpa.kernel.ExpressionStoreQuery > at org.apache.openjpa.kernel.ExpressionStoreQuery$DataStoreExecutor.executeQuery(ExpressionStoreQuery.java:674) > at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:979) > at org.apache.openjpa.kernel.QueryImpl.deleteInMemory(QueryImpl.java:1005) > ... 28 more > {code} > The proximate cause for the bug is that when the JDBCStoreQuery does this: > private Table getTable(FieldMapping fm, Table table) { > if (fm.getCascadeDelete() != ValueMetaData.CASCADE_NONE) > return INVALID; > it causes "isSingleTableMapping" to be considered false, which in turn permits executeBulkOperation to return null. Meanwhile, back in DataStoreExecutor: > public Number executeDelete(StoreQuery q, Object[] params) { > Number num = ((ExpressionStoreQuery) q).executeDelete(this, _meta, > _metas, _subs, _facts, _exps, params); > if (num == null) > return q.getContext().deleteInMemory(this, params); // <- now we have come here because executeDelete punted > return num; > } > So deleteInMemory gets called in QueryImpl: > public Number deleteInMemory(StoreQuery.Executor executor, > Object[] params) { > try { > Object o = execute(executor, params); > , but a DataStoreExecutor doesn't know how to execute the QueryCacheStoreQuery that it gets. > Somehwere, something is too unwrapped, or not wrapped enough. Good luck! > Workaround: > If A owns B, then instead of cascade=CascadeType.ALL, you can > @Entity > class A { > B myThing; > @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }) > B getMyThing() { return myThing; } > } > @Entity > class B { > A owner; > @ForeignKey(deleteAction=ForeignKeyAction.CASCADE) > A getOwner() { return owner; } > } -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.