persistence@glassfish.java.net

Re: cascaded remove failure on many-to-many relationship

From: Wonseok Kim <guruwons_at_gmail.com>
Date: Sun, 2 Jul 2006 10:52:48 +0900

Hi, Chris

I should have mentioned that both Team and Player has cascade=REMOVE
relationship.
See following

@Entity
@Table(name = "EJB_ROSTER_PLAYER")
public class Player implements java.io.Serializable {

    @ManyToMany(cascade = REMOVE, mappedBy = "players")
    public Collection<Team> getTeams() {
        return teams;
    }

@Entity
@Table(name = "EJB_ROSTER_TEAM")
public class Team implements java.io.Serializable {

    @ManyToMany(cascade = REMOVE)
    @JoinTable(name = "EJB_ROSTER_TEAM_PLAYER", joinColumns =
@JoinColumn(name = "TEAM_ID", referencedColumnName = "ID")
    , inverseJoinColumns = @JoinColumn(name = "PLAYER_ID",
referencedColumnName = "ID")
    )
    public Collection<Player> getPlayers() {
        return players;
    }

So when removing Team T6, it should remove P9, P21, P24, T2 and Players
related to T2.
v1 FCS does this, but current code has problem.

P.S. You can check this sample in Java EE 5 Tutorial examples/ejb/roaster.

On 6/30/06, Christopher Delahunt <christopher.delahunt_at_oracle.com> wrote:
>
> Hello Wonseok,
>
> Looks like you have the cascade=REMOVE set on the Team->Player
> relationship, but do you also have Player->Team set to cascade remove? If
> not, that would cause this issue.
>
> Problem is that you are removing Team T6 which cascades to P9, P21, and
> P24, but Team T2 still has a reference to P9. If you are going to remove
> Player P9, all other objects not being removed must have their references to
> it set to null, or they too must be removed.
>
> Best Regards,
> Chris
>
> ----- Original Message -----
> *From:* Wonseok Kim <guruwons_at_gmail.com>
> *To:* persistence_at_glassfish.dev.java.net
> *Sent:* Friday, June 30, 2006 7:26 AM
> *Subject:* cascaded remove failure on many-to-many relationship
>
> target: GlassFish v2 b08, Derby with java2db(ddl-generation)
>
> When running Java EE 5 tutorial ejb/roster sample application on trunk
> build, removing entities throws Exception - a violation of foreign key
> constraint. But GlassFish v1 FCS has no problem.
>
> Team and Player entity has bidirectional ManyToMany relationship with
> cascade=REMOVE.
>
> Client does something like following:
> P# is Player id,T# is Team id
>
> request.addPlayer("P9", "T2");
>
> request.addPlayer("P24", "T6");
> request.addPlayer("P21", "T6");
> request.addPlayer("P9", "T6");
>
> System.out.println("Removing team T6.");
> request.removeTeam("T6");
>
> <SERVER LOG>
> removeTeam
> DELETE FROM EJB_ROSTER_TEAM_PLAYER WHERE (TEAM_ID = ?)
> bind => [T6]|#]
> DELETE FROM EJB_ROSTER_TEAM WHERE (ID = ?)
> bind => [T6]|#]
> DELETE FROM EJB_ROSTER_PLAYER WHERE (ID = ?)
> bind => [P9]|#]
>
> Local Exception Stack:
> Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2006.6 (Build
> 060608)): oracle.toplink.essentials.exceptions.DatabaseException
> Internal Exception: org.apache.derby.client.am.SqlException: DELETE on
> table 'EJB_ROSTER_PLAYER' caused a violation of foreign key constraint
> 'JBRSTRTMPLYERPLYRD' for key (P9). The statement has been rolled
> back.Error Code: -1
> Call:DELETE FROM EJB_ROSTER_PLAYER WHERE (ID = ?)
> bind => [P9]
> Query:DeleteObjectQuery(roster.entity.Player_at_1bb121f)
> at
> oracle.toplink.essentials.exceptions.DatabaseException.sqlException (
> DatabaseException.java:295)
> at
> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect
> (DatabaseAccessor.java:639)
> at
> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeNoSelect(
> DatabaseAccessor.java:688)
> at
> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.basicExecuteCall
> (DatabaseAccessor.java:477)
> at
> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeCall(
> DatabaseAccessor.java:437)
> at
> oracle.toplink.essentials.internal.sessions.AbstractSession.executeCall(
> AbstractSession.java:675)
> at
> oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.executeCall(
> DatasourceCallQueryMechanism.java:213)
> at
> oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.executeCall
> (DatasourceCallQueryMechanism.java:199)
> at
> oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.deleteObject(
> DatasourceCallQueryMechanism.java:190)
> at
> oracle.toplink.essentials.internal.queryframework.StatementQueryMechanism.deleteObject
> (StatementQueryMechanism.java:115)
> at
> oracle.toplink.essentials.queryframework.DeleteObjectQuery.executeDatabaseQuery(
> DeleteObjectQuery.java:132)
> at oracle.toplink.essentials.queryframework.DatabaseQuery.execute(
> DatabaseQuery.java:609)
> at
> oracle.toplink.essentials.queryframework.DatabaseQuery.executeInUnitOfWork
> (DatabaseQuery.java :536)
> at
> oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery
> (ObjectLevelModifyQuery.java:123)
> at
> oracle.toplink.essentials.queryframework.DeleteObjectQuery.executeInUnitOfWorkObjectLevelModifyQuery(
> DeleteObjectQuery.java:95)
> at
> oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWork
> (ObjectLevelModifyQuery.java:95)
> at
> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(
> UnitOfWorkImpl.java:2218)
> at
> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(
> AbstractSession.java:937)
> at
> oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery (
> AbstractSession.java:894)
> at
> oracle.toplink.essentials.internal.sessions.CommitManager.deleteAllObjects
> (CommitManager.java:322)
> at
> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabase(
> UnitOfWorkImpl.java:1033)
> at
> oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.commitToDatabase
> (RepeatableWriteUnitOfWork.java:353)
> at
> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(
> UnitOfWorkImpl.java:1112)
> at
> oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion
> (UnitOfWorkImpl.java:2428)
> at
> oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(
> RepeatableWriteUnitOfWork.java:177)
> at
> oracle.toplink.essentials.transaction.AbstractSynchronizationListener.beforeCompletion
> (AbstractSynchronizationListener.java:116)
> at
> oracle.toplink.essentials.transaction.JTASynchronizationListener.beforeCompletion(
> JTASynchronizationListener.java:76)
> at
> com.sun.ejb.containers.ContainerSynchronization.beforeCompletion(
> ContainerSynchronization.java:154)
> at com.sun.enterprise.distributedtx.J2EETransaction.commit(
> J2EETransaction.java:395)
> at
> com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.commit(
> J2EETransactionManagerOpt.java:357)
> at com.sun.ejb.containers.BaseContainer.completeNewTx(
> BaseContainer.java :3653)
> at com.sun.ejb.containers.BaseContainer.postInvokeTx(
> BaseContainer.java:3431)
> at com.sun.ejb.containers.StatefulSessionContainer.postInvokeTx(
> StatefulSessionContainer.java:1292)
> at com.sun.ejb.containers.BaseContainer.postInvoke(
> BaseContainer.java:1247)
> at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(
> EJBObjectInvocationHandler.java:197)
> at
> com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke (
> EJBObjectInvocationHandlerDelegate.java:67)
> at $Proxy43.removeTeam(Unknown Source)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at sun.reflect.NativeMethodAccessorImpl.invoke (
> NativeMethodAccessorImpl.java:39)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(
> DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:585)
> at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke (
> ReflectiveTie.java:121)
> at
> com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant
> (CorbaServerRequestDispatcherImpl.java:650)
> at
> com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch (
> CorbaServerRequestDispatcherImpl.java:193)
> at
> com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest
> (CorbaMessageMediatorImpl.java:1705)
> at
> com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest (
> CorbaMessageMediatorImpl.java:1565)
> at
> com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(
> CorbaMessageMediatorImpl.java:947)
> at
> com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:178)
> at
> com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(
> CorbaMessageMediatorImpl.java:717)
> at
> com.sun.corba.ee.impl.transport.SocketOrChannelConnectionImpl.dispatch (
> SocketOrChannelConnectionImpl.java:473)
> at
> com.sun.corba.ee.impl.transport.SocketOrChannelConnectionImpl.doWork(
> SocketOrChannelConnectionImpl.java:1270)
> at
> com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run (
> ThreadPoolImpl.java:479)
> Caused by: org.apache.derby.client.am.SqlException: DELETE on table
> 'EJB_ROSTER_PLAYER' caused a violation of foreign key constraint
> 'JBRSTRTMPLYERPLYRD' for key (P9). The statement has been rolled back.
> at org.apache.derby.client.am.Statement.completeExecute(Unknown
> Source)
> at
> org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(Unknown
> Source)
> at org.apache.derby.client.net.NetStatementReply.readExecute(Unknown Source)
> at org.apache.derby.client.net.StatementReply.readExecute(Unknown
> Source)
> at org.apache.derby.client.net.NetPreparedStatement.readExecute_(Unknown
> Source)
> at org.apache.derby.client.am.PreparedStatement.readExecute(Unknown Source)
> at org.apache.derby.client.am.PreparedStatement.flowExecute(Unknown
> Source)
> at org.apache.derby.client.am.PreparedStatement.executeUpdateX(Unknown
> Source)
> at org.apache.derby.client.am.PreparedStatement.executeUpdate(Unknown Source)
> at
> oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect
> (DatabaseAccessor.java:632)
> ... 50 more
> |#]
>
> Cascaded remove should trigger more DELETE statements, but it didn't.
> Is it known issue? Or shall I file an issue for this?
>
> --
> Wonseok Kim
> Senior Developer, TmaxSoft
>
>


-- 
Wonseok Kim
Senior Developer, TmaxSoft