-->
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.  [ 10 posts ] 
Author Message
 Post subject: cascading saves problems...
PostPosted: Thu Sep 25, 2003 5:32 am 
Newbie

Joined: Thu Sep 25, 2003 5:03 am
Posts: 8
Hi All,

Been using Hibernate for about 2 weeks now and have run into the
following problem, hopefully someone out there knows what I'm doing
wrong. I've read the hibernate manual and checked the web for something
similar, but can't find anything like this, I must be doing something
stupid!

Before I describe the problem, I've read the FAQ at http://www.hibernate.org/117.html#A20

"Hibernate throws: Flush during cascade is dangerous.

This almost always happens because you forgot to remove a deleted instance from an association with cascading save enabled. You should remove deleted objects from associations before flushing the session."

I haven't removed ANY objects, it's when I try to remove the parent of the objects I've created this happens,

Thanks in advance for any help with this, its wrecking my head!!!!


Bascally I create some objects persist them in a method, which is the
setUp of a JUnit Test.

I run a method which makes some changes to the objects after it
retrieves them from the DAO.

I use the JUnit tearDown() method to delete the objects, which then
throws the Exception, the test has passed, the contents are in the DB,
I've checked this by hand.

We have something like the following structure, with the domain objects:

Airline
Account
CardHolder

The xdoclet tags look like this:

/**
* @return
* @hibernate.set cascade="all" lazy="false"
* @hibernate.collection-key column="AIRLINE_ID"
* @hibernate.collection-one-to-many
class="com.universalred.domain.CardHolder"
* @todo should probably be a list
*/
Airline has a one to many relationship with CardHolder

/**
* @return
*
* @hibernate.one-to-one class="com.universalred.domain.Account"
cascade="all"
*/
/**
* @return
* @hibernate.many-to-one class="com.universalred.domain.Airline"
column="AIRLINE_ID" not-null="false"
*/
CardHolder has an one to one relationship with Account and many to one
with Airline


When we do a delete on Airline it give us the following exception:


com.universalred.dao.DAOException: net.sf.hibernate.HibernateException:
Flush during cascade is dangerous - this might occur if an object was
deleted and then re-saved by cascade
at
com.universalred.dao.hibernate.BaseDAOHibernate.delete(BaseDAOHibernate.
java:218)
at
com.universalred.dao.hibernate.AirlineDAOHibernate.delete(AirlineDAOHibe
rnate.java:46)
at
com.universalred.io.FileEventAdaptorTest.tearDown(FileEventAdaptorTest.j
ava:116)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTe
stRunner.java:392)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRun
ner.java:276)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRu
nner.java:167)
Caused by: net.sf.hibernate.HibernateException: Flush during cascade is
dangerous - this might occur if an object was deleted and then re-saved
by cascade
at
net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2001)
at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:589)
at
net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1187)
at net.sf.hibernate.engine.Cascades$3.cascade(Cascades.java:88)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:258)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:341)
at
net.sf.hibernate.impl.SessionImpl.preFlushEntities(SessionImpl.java:2285
)
at
net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2015)
at
net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2004)
at
com.universalred.dao.hibernate.BaseDAOHibernate.delete(BaseDAOHibernate.
java:214)
... 12 more

I use this method given below to delete Objects, would it be possible
that the ses.delete(obj) method has started some thread that hasn't
finished?

protected synchronized void delete(Object obj) throws DAOException {
Session ses = null;

try {

ses = ThreadLocalSession.currentSession();

if (ses == null) {
throw new DAOException("No Session.");
}
ses.delete(obj);
ses.flush();

} catch (Exception e) {

throw new DAOException(e);

}

This is the method I use to save:

/**
* Save the given domain object to the database.
*
* @param obj
* @throws DAOException
*/
protected synchronized void save(Object obj) throws DAOException {
Session ses = null;

try {
ses = ThreadLocalSession.currentSession();
ses.saveOrUpdate(obj);
// @TODO remove this flush if it is not needed
ses.flush();
} catch (Exception e) {
try {
ses.connection().rollback();
} catch (Exception ex) {
e.printStackTrace();
};
throw new DAOException(e);
}
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 25, 2003 10:04 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
When you delete an object, you must remove the object from any associations mapped with cascade="save-update". The exception message is incredibly self-explanatory.


Top
 Profile  
 
 Post subject: Apologies please follow our progress at thisthread
PostPosted: Thu Sep 25, 2003 10:39 am 
Newbie

Joined: Thu Sep 25, 2003 5:03 am
Posts: 8
Hi Gavin,

thanks for the reply, much appreciated,

I noticed a similar problem while browsing the forums looking for a solution, so I threw my hat in and gave a fix to the other persons problem, and my own. I didn't want to give a half fix to this post, I wanted to try everything I could first, you can see our progress below:

http://forum.hibernate.org/viewtopic.php?p=2860#2860

This problem occurs when we delete the parent object, not the child - does this mean we have to go down through the entire object tree to delete a parent, this seems a bit arkward. I have to tarverse through all child objects and delete the references to the parent?

If I turn caching off by removing the object using session.evict(obj) after every save / delete this problem went away completely and everything works as expected- we're attempting to solve this on the other thread now, but it looks like we'll have to use transactions to solve it, also we have a helper class that we use to cache Session objects, as per below.

Thanks for your help with this, and again I'm sorry for posting to the wrong mailing list, I didn't intend to mess up your list with newbie problems!

As I said on the other thread, amazing support from the hibernate team and users, much faster and clearer answers than other *big* companies I've dealt with in the past,

thanks...

here's the way we cache/get sessions, after davids advice I'm gonna try use very short lived sessions and see if that makes a difference.


private static Session currentSession(boolean increment) throws DAOException {
if (factory == null) {
try {
Configuration config = new Configuration().
addClass(Airline.class).
addClass(Person.class).
addClass(Account.class).
addClass(Card.class).
addClass(Statement.class).
addClass(EmployeeCategory.class).
addClass(CardTransaction.class).
addClass(CurrencyStore.class).
addClass(FileAudit.class).
addClass(BillingTarrif.class).
addClass(AirlineBillingLedger.class).
addClass(Contact.class).
addClass(AirlineBillingStatement.class);
factory = config.buildSessionFactory();
} catch (HibernateException e) {
throw new DAOException(e);
}
}
ThreadLocalSession tlSession = (ThreadLocalSession)sessionContext.get();
if (tlSession == null) {
tlSession = new ThreadLocalSession();
try {
tlSession.session = factory.openSession();
} catch (HibernateException e) {
throw new DAOException(e);
}
tlSession.level = 0;
sessionContext.set(tlSession);
}
tlSession.level++;
return tlSession.session;
}

public static Session currentSession() throws DAOException {
return currentSession(true);
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2003 5:37 am 
Beginner
Beginner

Joined: Fri Sep 26, 2003 2:50 am
Posts: 32
my examples' code is as following,

Operation.java
Code:
package test;

import java.util.Set;

/**
* @hibernate.class table="T_Operation"
*/
public class Operation {
  private String id;
  private String parentId;
  private String operName;
  private String imageFile;
  private String url;
  private String description;

  /* 该操作所在的组信息,其中保存的应当是Group类型的数据 */
  private Set groups;

  /* 该操作的子操作的信息,其中保存的还是Operation类型的对象 */
  private Set operations;

  /* 可以进行该项操作的所有操作员的信息 */
  private Set users;

  /* 当前操作的父操作的对象 */
  private Operation parent;

  /**
   * @hibernate.id generator-class="assigned" type="string" column="OperID"
   * @return
   */
  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  /**
   * @hibernate.property column="ParentID" type="string" insert="false" update="false"
   * @return
   */
  public String getParentId() {
    return parentId;
  }

  public void setparentId(String id) {
    this.parentId = id;
  }

  /**
   * @hibernate.property column="OperName" type="string"
   * @return
   */
  public String getOperName() {
    return operName;
  }

  public void setOperName(String name) {
    this.operName = name;
  }

  /**
   * @hibernate.property column="ImageFile" type="string"
   * @return
   */
  public String getImageFile() {
    return imageFile;
  }

  public void setImageFile(String file) {
    this.imageFile = file;
  }

  /**
   * @hibernate.property column="URL" type="string"
   * @return
   */
  public String getUrl() {
    return this.url;
  }

  public void setUrl(String url) {
    this.url = url;
  }

  /**
   * @hibernate.property column="Description" type="string"
   * @return
   */
  public String getDescription() {
    return this.description;
  }

  public void setDescription(String desp) {
    this.description = desp;
  }

  /**
   * @hibernate.set role="groups" table="T_GroupRights"
   *                cascade="all" readonly="true" inverse="true"
   * @hibernate.collection-key column="OperID"
   * @hibernate.collection-many-to-many class="test.Group" column="GroupID"
   * @return
   */
  public Set getGroups() {
    return this.groups;
  }

  public void setGroups(Set groups) {
    this.groups = groups;
  }

  /**
   * @hibernate.set role="users" table="T_UserRights" lazy="true"
   *                cascade="none"
   * @hibernate.collection-key column="OperID"
   * @hibernate.collection-many-to-many class="test.User" column="UserID"
   * @return
   */
  public Set getUsers() {
    return this.users;
  }

  public void setUsers(Set users) {
    this.users = users;
  }

  /**
   * @hibernate.many-to-one role="parent" column="ParentID"
   *                        class="test.Operation" cascade="none" not-null="true"
   */
  public Operation getParent() {
    return parent;
  }

  public void setParent(Operation oper) {
    parent = oper;
  }

  /**
   * @hibernate.set role="ChildOpers" table="T_Operations"
   *                cascade="none" readonly="true" lazy="true" inverse="true"
   * @hibernate.collection-key column="ParentID"
   * @hibernate.collection-one-to-many class="test.Operation"
   * @param opers
   * @return
   */
  public Set getOperations() {
    return operations;
  }

  public void setOperations(Set opers) {
    this.operations = opers;
  }
}



User.java
Code:
package test;

import java.util.Set;

/**
* @hibernate.class table="T_User"
* @author Jack Zhuo
*/
public class User {
  private String id;
  private String staffid;
  private String password;
  private String groupid;
  private int type;

  /* 操作员所在的组 */
  private Group group;

  /* 该操作员可以进行的权限信息*/
  private Set operations;

  public User() {
  }

  /**
   * @hibernate.id generator-class="assigned" type="string"
   *             column="UserID"
   * @return
   */
  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  /**
   * @hibernate.property column="StaffID" type="string"
   * @return
   */
  public String getStaffid() {
    return this.staffid;
  }

  public void setStaffid(String sid) {
    this.staffid = sid;
  }

  /**
   * @hibernate.property column="Password" type="string"
   * @return
   */
  public String getPassword() {
    return this.password;
  }

  public void setPassword(String passwd) {
    this.password = passwd;
  }

  /**
   * hibernate.property column="GroupID" type="string"
   * @return
   */
  public String getGroupid() {
    return this.groupid;
  }

  public void setGroupid(String gid) {
    this.groupid = gid;
  }

  /**
   * @hibernate.property column="Type" type="int"
   * @return
   */
  public int getType() {
    return type;
  }

  public void setType(int type) {
    this.type = type;
  }

  /**
   * @hibernate.many-to-one role="group" column="GroupID"
   *                        class="test.Group" cascade="none" not-null="true"
   */
  public Group getGroup() {
    return this.group;
  }

  public void setGroup( Group group) {
    this.group = group;
  }

  /**
   * @hibernate.set role="operations" table="T_UserRights" cascade="none" lazy="true"
   * @hibernate.collection-key column="UserID"
   * @hibernate.collection-many-to-many class="test.Operation" column="OperID"
   * @return
   */
  public Set getOperations() {
    return this.operations;
  }

  public void setOperations(Set opers) {
    this.operations = opers;
  }
}



Group.java
Code:
package test;

import java.util.Set;

/**
* @hibernate.class table="T_Group"
*/
public class Group {
  private String id;
  private String groupName;
  private String description;
  private int type;

  /* 该组中所有的操作信息 */
  private Set operations;

  /* 该组中所有的操作员信息 */
  private Set users;

  /**
   * @hibernate.id generator-class="assigned" type="string" column="GroupID"
   * @return
   */
  public String getId() {
    return id;
  }

  public void setId(String id) { this.id = id; }

  /**
   * @hibernate.property column="GroupName" type="string"
   * @return
   */
  public String getGroupName() {
    return this.groupName;
  }

  public void setGroupName(String name) {
    this.groupName = name;
  }

  /**
   * @hibernate.property column="Description" type="string"
   * @return
   */
  public String getDescription() {
    return this.description;
  }

  public void setDescription(String desp) {
    this.description = desp;
  }

  /**
   * @hibernate.property column="Type" type="int"
   * @return
   */
  public int getType() {
    return type;
  }

  public void setType(int type) {
    this.type = type;
  }

  /**
   * @hibernate.set role="operations" table="T_GroupRights" cascade="all"
   * @hibernate.collection-key column="GroupID"
   * @hibernate.collection-many-to-many class="test.Operation" column="OperID"
   * @return
   */
  public Set getOperations() {
    return operations;
  }

  public void setOperations(Set opers) {
    this.operations = opers;
  }

  /**
   * @hibernate.set role="users" table="T_User" cascade="all"
   * @hibernate.collection-key column="GroupID"
   * @hibernate.collection-one-to-many class="test.User" column="GroupID"
   * @return
   */
  public Set getUsers() {
    return users;
  }

  public void setUsers(Set users) {
    this.users = users;
  }
}



Test.java: this is the client program!
Code:
package test;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;
import java.util.Set;
import java.util.HashSet;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;

public class Test {

  public static void main(String[] args) {
    run();
  }

  public static void run() {
    Configuration cfg = null;
    SessionFactory sf = null;
    Session session = null;

    try {
      cfg =
          new Configuration()
          .addClass(Operation.class)
          .addClass(Group.class)
          .addClass(User.class);

      sf = cfg.buildSessionFactory();
      // create a session object from the factory
      session = sf.openSession();

      User user = new User();
      user = (User) session.load(User.class, "test");
      Transaction tx = session.beginTransaction();
      session.delete(user);
      tx.commit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    finally {
      try {
        Connection con = session.close();
      }
      catch (HibernateException he) {
        System.out.println("HibernateException " + he.getMessage());
      }
    }
  }
}


please check these codes, it will throw :
net.sf.hibernate.HibernateException: Flush during cascade is dangerous - this might occur if an object was deleted and then re-saved by cascade (remove deleted object from associations)

thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2003 9:13 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
This is quite expected.

Either
* enable cascade delete
* call child.setParent(null) for each child


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2003 9:51 am 
Newbie

Joined: Thu Sep 25, 2003 5:03 am
Posts: 8
Hi Gavin,
thanks for the reply,

we do have cascade delete enabled on our parent, but we still get the same problems, does this mean we'll have to do child.setParent(null) for each child before we delete the parent?

Here's the javadoc for our parent - child relationship:

/**
* @return
* @hibernate.set cascade="all"
* @hibernate.collection-key column="AIRLINE_ID"
* @hibernate.collection-one-to-many class="com.universalred.domain.CardHolder"
* @todo should probably be a list
*/

public Set getCardHolders() {
return cardHolders;
}

Where com.universalred.domain.CardHolder is the child.

on the child we have


/**
* @return
* @hibernate.many-to-one class="com.universalred.domain.Airline" column="AIRLINE_ID" not-null="false"
*/

public Airline getAirline() {
return airline;
}

Does this look right? Or do we have to go and do a setparent(null) for each child?

Thanks in advance,


Oisin


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2003 12:57 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Look, I can tell from the stacktrace that a cascade is causing a deleted object to be re-saved. I suggest you stop posting here, and take _seriously_ the advice I have already given you. You have a complex mapping with several associations. Simplify it and isolate your problem! You should never ever post questions here until you have taken the time to narrow the problem down much further than you have done so far.


Top
 Profile  
 
 Post subject: Why do you have cascade="none" if you want to casc
PostPosted: Fri Sep 26, 2003 2:02 pm 
Senior
Senior

Joined: Sun Aug 31, 2003 3:14 pm
Posts: 151
Location: Earth (at the moment)
I think that if you want the children to live on without their parent then you will need to set the parent reference to null for each of them, if however you want the children to be deleted along with the parent then set the cascades accordingly, I'm not familiar with using XDoclet to generate Hibernate mappings but it looks to me like you've got lots of children set with cascade="none".
eg:
Code:
   * @hibernate.set role="users" table="T_UserRights" lazy="true"
   *                cascade="none"

   * @hibernate.many-to-one role="parent" column="ParentID"
   *                        class="test.Operation" cascade="none" not-null="true"

   * @hibernate.set role="ChildOpers" table="T_Operations"
   *                cascade="none" readonly="true" lazy="true" inverse="true"

Hope that helps.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2003 9:44 pm 
Beginner
Beginner

Joined: Fri Sep 26, 2003 2:50 am
Posts: 32
gavin wrote:
Look, I can tell from the stacktrace that a cascade is causing a deleted object to be re-saved. I suggest you stop posting here, and take _seriously_ the advice I have already given you. You have a complex mapping with several associations. Simplify it and isolate your problem! You should never ever post questions here until you have taken the time to narrow the problem down much further than you have done so far.



Thanks Given, I will try like you say firstly.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 26, 2003 10:54 pm 
Beginner
Beginner

Joined: Fri Sep 26, 2003 2:50 am
Posts: 32
YES! the problem is solved!!!!!!

Thanks Given and everyone!Thanks a lot!

Because Table T_User associate with both T_Group and T_Operation, like Given adviced, I just test the association between T_User and T_Group, it is one-to-many. and then test all associations.

this is the result:
for one-to-many:
at 'one' hand: set cascade="none" this is required.
at 'many' hand" set casecase="save-update"

for many-to-many:
antt any hand, cascade must be set to "none" or "save-update". I try to setting "all" or "delete", but it still has problem.

to Given:
Is it right?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 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.