-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: on-delete="cascade" conflicted with cascade="
PostPosted: Fri Feb 18, 2005 1:06 pm 
Regular
Regular

Joined: Thu Dec 02, 2004 7:11 am
Posts: 85
Hibernate version: Hibernate 3.0 beta 4

Mapping documents:

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping default-access="field">

<class name="Parent" table="Parent">
<id name="id" column="ParentID" type="integer">
<generator class="native"/>
</id>

<set name="childs" lazy="true" inverse="true" cascade="all-delete-orphan">
<key column="ParentID" on-delete="cascade"/>
<one-to-many class="Child"/>
</set>
</class>

<class name="Child" table="Child">
<id name="id" column="ChildID" type="integer">
<generator class="native"/>
</id>

<many-to-one name="parent" column="ParentID" not-null="true" cascade="none"
foreign-key="FK_Child_Parent"/>

<many-to-one name="subChild" column="SubChildID" cascade="all"
foreign-key="FK_Child_SubChild"/>

</class>

<class name="SubChild" table="SubChild">
<id name="id" column="SubChildID" type="integer">
<generator class="native"/>
</id>
</class>

</hibernate-mapping>

Code between sessionFactory.openSession() and session.close():

public static void main(String args[])
{
Configuration cfg = new Configuration();

cfg.configure("hibernate.cfg.xml");

cfg.setProperty(Environment.HBM2DDL_AUTO, "create");

SessionFactory factory = cfg.buildSessionFactory();

addTestData(factory);

deleteTestData(factory);

factory.close();
}

static void addTestData(SessionFactory factory)
{
Session s = factory.openSession();

Transaction tx=null;

try
{
tx = s.beginTransaction();

Parent parent = new Parent();

Child child = new Child();

child.setSubChild( new SubChild() );

parent.addChild(child);

s.save(parent);

tx.commit();
}
catch( RuntimeException e )
{
if (tx!=null) tx.rollback();
throw e;
}
finally { s.close(); }
}

static void deleteTestData(SessionFactory factory)
{
Session s = factory.openSession();

Transaction tx=null;

try
{
tx = s.beginTransaction();

List<Parent> list = (List<Parent>)s.createCriteria(Parent.class).list();

for( Parent parent: list )
{
System.out.println("Deleting "+parent);

s.delete(parent);
}

tx.commit();
}
catch( RuntimeException e )
{
if (tx!=null) tx.rollback();
throw e;
}
finally { s.close(); }

Full stack trace of any exception that occurs:

org.hibernate.exception.ConstraintViolationException: could not delete: [SubChild#1]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:63)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.BasicEntityPersister.delete(BasicEntityPersister.java:2005)
at org.hibernate.persister.BasicEntityPersister.delete(BasicEntityPersister.java:2133)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:61)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:271)
at org.hibernate.event.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:24)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:719)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:84)
at OnDeleteTest.deleteTestData(OnDeleteTest.java:74)
at OnDeleteTest.main(OnDeleteTest.java:20)
Caused by: java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]DELETE statement conflicted with COLUMN REFERENCE constraint 'FK_Child_SubChild'. The conflict occurred in database 'BirdDB', table 'Child', column 'SubChildID'.
at com.microsoft.jdbc.base.BaseExceptions.createException(Unknown Source)
at com.microsoft.jdbc.base.BaseExceptions.getException(Unknown Source)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processErrorToken(Unknown Source)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReplyToken(Unknown Source)
at com.microsoft.jdbc.sqlserver.tds.TDSRPCRequest.processReplyToken(Unknown Source)
at com.microsoft.jdbc.sqlserver.tds.TDSRequest.processReply(Unknown Source)
at com.microsoft.jdbc.sqlserver.SQLServerImplStatement.getNextResultType(Unknown Source)
at com.microsoft.jdbc.base.BaseStatement.commonTransitionToState(Unknown Source)
at com.microsoft.jdbc.base.BaseStatement.postImplExecute(Unknown Source)
at com.microsoft.jdbc.base.BasePreparedStatement.postImplExecute(Unknown Source)
at com.microsoft.jdbc.base.BaseStatement.commonExecute(Unknown Source)
at com.microsoft.jdbc.base.BaseStatement.executeUpdateInternal(Unknown Source)
at com.microsoft.jdbc.base.BasePreparedStatement.executeUpdate(Unknown Source)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
at org.hibernate.persister.BasicEntityPersister.delete(BasicEntityPersister.java:1988)
... 11 more

Name and version of the database you are using:
MSSQL 2000 SP3 Desktop Edition

The generated SQL (show_sql=true):

Hibernate: insert into Parent default values select scope_identity()
Hibernate: insert into SubChild default values select scope_identity()
Hibernate: insert into Child (ParentID, SubChildID) values (?, ?) select scope_identity()
Hibernate: select this_.ParentID as ParentID0_ from Parent this_
Hibernate: select childs0_.ParentID as ParentID__, childs0_.ChildID as ChildID__, childs0_.ChildID as ChildID0_, childs0_.ParentID as ParentID1_0_, childs0_.SubChildID as SubChildID1_0_ from Child childs0_ where childs0_.ParentID=?
Hibernate: select subchild0_.SubChildID as SubChildID0_ from SubChild subchild0_ where subchild0_.SubChildID=?
Hibernate: delete from SubChild where SubChildID=?

Debug level Hibernate log excerpt:

Excerpt from log starting from object deleting:

DEBUG hibernate.event.DefaultDeleteEventListener - deleting a persistent instance
DEBUG hibernate.event.DefaultDeleteEventListener - deleting [Parent#1]
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.engine.Cascades - processing cascade ACTION_DELETE for: Parent
DEBUG hibernate.engine.Cascades - cascade ACTION_DELETE for collection: Parent.childs
DEBUG hibernate.event.DefaultInitializeCollectionEventListener - initializing collection [Parent.childs#1]
DEBUG hibernate.event.DefaultInitializeCollectionEventListener - checking second-level cache
DEBUG hibernate.event.DefaultInitializeCollectionEventListener - collection not cached
DEBUG hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG org.hibernate.SQL - select childs0_.ParentID as ParentID__, childs0_.ChildID as ChildID__, childs0_.ChildID as ChildID0_, childs0_.ParentID as ParentID1_0_, childs0_.SubChildID as SubChildID1_0_ from Child childs0_ where childs0_.ParentID=?
DEBUG hibernate.jdbc.AbstractBatcher - preparing statement
DEBUG hibernate.type.IntegerType - binding '1' to parameter: 1
DEBUG hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
DEBUG hibernate.loader.Loader - result set contains (possibly empty) collection: [Parent.childs#1]
DEBUG hibernate.engine.CollectionLoadContext - uninitialized collection: initializing
DEBUG hibernate.loader.Loader - processing result set
DEBUG hibernate.loader.Loader - result set row: 0
DEBUG hibernate.type.IntegerType - returning '1' as column: ChildID0_
DEBUG hibernate.loader.Loader - result row: EntityKey[Child#1]
DEBUG hibernate.loader.Loader - Initializing object from ResultSet: [Child#1]
DEBUG hibernate.persister.BasicEntityPersister - Hydrating entity: [Child#1]
DEBUG hibernate.type.IntegerType - returning '1' as column: ParentID1_0_
DEBUG hibernate.type.IntegerType - returning '1' as column: SubChildID1_0_
DEBUG hibernate.type.IntegerType - returning '1' as column: ParentID__
DEBUG hibernate.loader.Loader - found row of collection: [Parent.childs#1]
DEBUG hibernate.engine.CollectionLoadContext - reading row
DEBUG hibernate.type.IntegerType - returning '1' as column: ChildID__
DEBUG hibernate.event.DefaultLoadEventListener - loading entity: [Child#1]
DEBUG hibernate.event.DefaultLoadEventListener - entity found in session cache
DEBUG hibernate.event.DefaultLoadEventListener - attempting to resolve: [Child#1]
DEBUG hibernate.event.DefaultLoadEventListener - resolved object in session cache: [Child#1]
DEBUG hibernate.loader.Loader - done processing result set (1 rows)
DEBUG hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
DEBUG hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG hibernate.jdbc.AbstractBatcher - closing statement
DEBUG hibernate.loader.Loader - total objects hydrated: 1
DEBUG hibernate.engine.TwoPhaseLoad - resolving associations for [Child#1]
DEBUG hibernate.event.DefaultLoadEventListener - loading entity: [Parent#1]
DEBUG hibernate.event.DefaultLoadEventListener - entity found in session cache
DEBUG hibernate.event.DefaultLoadEventListener - attempting to resolve: [Parent#1]
DEBUG hibernate.event.DefaultLoadEventListener - resolved object in session cache: [Parent#1]
DEBUG hibernate.event.DefaultLoadEventListener - loading entity: [SubChild#1]
DEBUG hibernate.event.DefaultLoadEventListener - creating new proxy for entity
DEBUG hibernate.engine.TwoPhaseLoad - done materializing entity [Child#1]
DEBUG hibernate.engine.CollectionLoadContext - 1 collections were found in result set
DEBUG hibernate.engine.CollectionLoadContext - collection fully initialized: [Parent.childs#1]
DEBUG hibernate.engine.CollectionLoadContext - 1 collections initialized
DEBUG hibernate.engine.PersistenceContext - initializing non-lazy collections
DEBUG hibernate.event.DefaultInitializeCollectionEventListener - collection initialized
DEBUG hibernate.engine.Cascades - cascading to delete: Child
DEBUG hibernate.event.DefaultDeleteEventListener - deleting a persistent instance
DEBUG hibernate.event.DefaultDeleteEventListener - deleting [Child#1]
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.engine.Cascades - processing cascade ACTION_DELETE for: Child
DEBUG hibernate.engine.Cascades - done processing cascade ACTION_DELETE for: Child
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.engine.Cascades - processing cascade ACTION_DELETE for: Child
DEBUG hibernate.engine.Cascades - cascading to delete: SubChild
DEBUG hibernate.event.DefaultLoadEventListener - attempting to resolve: [SubChild#1]
DEBUG hibernate.event.DefaultLoadEventListener - object not resolved in any cache: [SubChild#1]
DEBUG hibernate.persister.BasicEntityPersister - Materializing entity: [SubChild#1]
DEBUG hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG org.hibernate.SQL - select subchild0_.SubChildID as SubChildID0_ from SubChild subchild0_ where subchild0_.SubChildID=?
DEBUG hibernate.jdbc.AbstractBatcher - preparing statement
DEBUG hibernate.type.IntegerType - binding '1' to parameter: 1
DEBUG hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
DEBUG hibernate.loader.Loader - processing result set
DEBUG hibernate.loader.Loader - result set row: 0
DEBUG hibernate.loader.Loader - result row: EntityKey[SubChild#1]
DEBUG hibernate.loader.Loader - Initializing object from ResultSet: [SubChild#1]
DEBUG hibernate.persister.BasicEntityPersister - Hydrating entity: [SubChild#1]
DEBUG hibernate.loader.Loader - done processing result set (1 rows)
DEBUG hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
DEBUG hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG hibernate.jdbc.AbstractBatcher - closing statement
DEBUG hibernate.loader.Loader - total objects hydrated: 1
DEBUG hibernate.engine.TwoPhaseLoad - resolving associations for [SubChild#1]
DEBUG hibernate.engine.TwoPhaseLoad - done materializing entity [SubChild#1]
DEBUG hibernate.engine.PersistenceContext - initializing non-lazy collections
DEBUG hibernate.event.DefaultDeleteEventListener - deleting a persistent instance
DEBUG hibernate.event.DefaultDeleteEventListener - deleting [SubChild#1]
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.engine.Cascades - done processing cascade ACTION_DELETE for: Child
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.engine.Cascades - done cascade ACTION_DELETE for collection: Parent.childs
DEBUG hibernate.engine.Cascades - deleting orphans for collection: Parent.childs
DEBUG hibernate.engine.Cascades - done deleting orphans for collection: Parent.childs
DEBUG hibernate.engine.Cascades - done processing cascade ACTION_DELETE for: Parent
DEBUG hibernate.impl.SessionImpl - setting cache mode to: NORMAL
DEBUG hibernate.impl.SessionImpl - setting cache mode to: GET
DEBUG hibernate.engine.Cascades - processing cascade ACTION_DELETE for: Parent
DEBUG hibernate.engine.Cascades - done processing cascade ACTION_DELETE for: Parent
DEBUG hibernate.impl.SessionImpl - setting cache mode to: NORMAL
DEBUG hibernate.transaction.JDBCTransaction - commit
DEBUG hibernate.event.AbstractFlushingEventListener - flushing session
DEBUG hibernate.event.AbstractFlushingEventListener - processing flush-time cascades
DEBUG hibernate.event.AbstractFlushingEventListener - dirty checking collections
DEBUG hibernate.event.AbstractFlushingEventListener - Flushing entities and processing referenced collections
DEBUG hibernate.event.AbstractFlushingEventListener - Processing unreferenced collections
DEBUG hibernate.engine.Collections - Collection dereferenced: [Parent.childs#1]
DEBUG hibernate.event.AbstractFlushingEventListener - Scheduling collection removes/(re)creates/updates
DEBUG hibernate.event.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 3 deletions to 3 objects
DEBUG hibernate.event.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 1 removals to 1 collections
DEBUG hibernate.pretty.Printer - listing entities:
DEBUG hibernate.pretty.Printer - SubChild{id=1}
DEBUG hibernate.pretty.Printer - Child{subChild=SubChild#1, parent=Parent#1, id=1}
DEBUG hibernate.pretty.Printer - Parent{childs=[Child#1], id=1}
DEBUG hibernate.event.AbstractFlushingEventListener - executing flush
DEBUG hibernate.persister.BasicEntityPersister - Deleting entity: [SubChild#1]
DEBUG hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG org.hibernate.SQL - delete from SubChild where SubChildID=?
DEBUG hibernate.jdbc.AbstractBatcher - preparing statement
DEBUG hibernate.type.IntegerType - binding '1' to parameter: 1
DEBUG hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG hibernate.jdbc.AbstractBatcher - closing statement
DEBUG hibernate.util.JDBCExceptionReporter - could not delete: [SubChild#1] [delete from SubChild where SubChildID=?]
java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]DELETE statement conflicted with COLUMN REFERENCE constraint 'FK_Child_SubChild'. The conflict occurred in database 'BirdDB', table 'Child', column 'SubChildID'.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 28, 2005 10:29 am 
Regular
Regular

Joined: Thu Dec 02, 2004 7:11 am
Posts: 85
So, can anyone comment this issue? Is this a bug or a feature?

As I understand, there is a problem with ordering of DELETE operators.

When I call session.delete(parent), Hibernate processing cascades and sheduled 3 DELETE operators (in this order: DELETE FROM Child, DELETE FROM SubChild, DELETE FROM Parent). However, due on-cascade="cascade" declaration in Parent->Child relation, deleting from Child is not invoked (since deleting of Parent should do this, only later).

Workaround there - removing on-delete="cascade" declaration. Is this the only way?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 28, 2005 10:46 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Seems reasonable to me. Alternatively disable cascade delete on the <many-to-one> to the subchild (cascade delete on a many-to-one is usually semantically wrong anyway...)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 28, 2005 11:21 am 
Regular
Regular

Joined: Thu Dec 02, 2004 7:11 am
Posts: 85
Quote:
cascade delete on a many-to-one is usually semantically wrong anyway...


Sure, when this relation is used as real many-to-one. But there is a cases, when this relation used as replacement of one-to-one (suggestion of using 'a foreign key with a unique constraint' from reference, section 5.1.11).


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.