Cascade not working in Hibernate? Help needed!

Discussions

General J2EE: Cascade not working in Hibernate? Help needed!

  1. Cascade not working in Hibernate? Help needed! (5 messages)

    Hi everyone,

    I've been having more trouble with Hibernate lately. I'll try to be very brief in my description - I need help here, I'm completely out of ideas.

    In my application, I have a User object that contains as one of its properties a Set of Log objects - representing all log entries for that particular user.

    Here is the mapping document for the User class:

    <class name="UserBean" table="usr">
      <id name="id" column="usr_id" type="integer">
        <generator class="native"/>
      </id>
      <property name="username" column="usr_nm"/>
      <property name="password" column="usr_pswrd"/>
      <set name="logs" table="lg" cascade="all">
        <key column="usr_id"/>
        <one-to-many class="LogBean"/>
      </set>
    </class>

    So as you can see, the Log entries are kept in a table called 'lg' that all have a foreign key 'usr_id' referring to a user.

    If I look up a User object, and check its Set of log entries, it contains all of them. However, if I remove a log from this set then save or update the user:

    Set logs = user.getLogs();
    Log log = logs.get(0);
    logs.remove(log);
    session.saveOrUpdate(user);

    This works, it saves the user, however, the log is not deleted from the database. Am I misunderstanding how cascading deletion should work, or is something wrong?

    Any help is greatly appreciated.

    Joe
  2. I am not a Hibernate expert, as I am only starting with it myself.. :)

    First of all, it would help to see definition for the LogBean class as well.

    Without seeing it, I would check that the LogBean class is not defined as mutable="false".

    Second, I'd create a reverse mapping in the LogBean class to Users, and specify inverse="true".

    I don't have the book on me, but if you send the XML for LogBean class I can look it up later.

    Hope this helps,
    Konstantin
  3. I am not a Hibernate expert, as I am only starting with it myself.. :)First of all, it would help to see definition for the LogBean class as well.Without seeing it, I would check that the LogBean class is not defined as mutable="false".Second, I'd create a reverse mapping in the LogBean class to Users, and specify inverse="true".I don't have the book on me, but if you send the XML for LogBean class I can look it up later.Hope this helps,Konstantin

    Hi there! (please I apologize for my poor english, english it's not my mother tongue)

    I'm having almost the same problem described in the original message.

    My .hbm files are:

    UserInfo (Parent):
    <hibernate-mapping>
      <class name="com.reuters.bean.UserInfo" table="sac_userinfo">
    <id name="id" column="user_info_id" type="long" unsaved-value="null">
    ...
        <set name="tasks" inverse="true" cascade="all" lazy="false">
          <key column="user_info_id" />
          <one-to-many class="com.reuters.bean.TaskInfo" />
        </set>
      </class>
    </hibernate-mapping>

    TaskInfo (Child):
    <hibernate-mapping>
      <class name="com.reuters.bean.TaskInfo" table="sac_taskinfo" mutable="true">

        <id name="id" column="task_info_id" type="long" unsaved-value="null">
    <generator class="native"/>
        </id>
    ...
        <many-to-one name="userInfo" class="com.reuters.bean.UserInfo" column="user_info_id" not-null="true" />
      </class>
    </hibernate-mapping>

    I have two DAO objects, one for Parent and one for Child objects extending a BaseDAO object.

    In BaseDAO object I have:

        protected void removeObj(Class c, Long id) throws DAOException {
            try {
                Session session = HibernateSession.currentSession();
                // first load the object with the current session.
                // the object must be loaded in this session before it
                // is deleted.
                Object obj = session.load(c, id);
                session.delete(obj);
                session.flush();
                session.connection().commit();
            } catch (Exception e) {
                rollback();
                throw new DAOException(e);
            } finally {
                closeSession();
            }
        }

    In TaskInfoDAO I have:

        public void removeTaskInfo(TaskInfo t) throws DAOException {
            removeTaskInfo(t.getId());
        }

        public void removeTaskInfo(Long id) throws DAOException {
            removeObj(TaskInfo.class, id);
        }
    (Also in UserInfoDAO I have two equivalent methods for UserInfo object)

    And my problematic code is:

            UserInfo userInfo = userInfoDAO.getUser(Long.valueOf(userInfoId));
            if (this.getUserInfoId() == null) {
                System.out.println("userInfo (" + userInfoId
                        + ") doesn't exist...");
                isSaved = false;
            } else {
                for (Iterator iter = userInfo.getTasks().iterator(); iter.hasNext();) {
                    TaskInfo element = (TaskInfo) iter.next();
                    userInfo.getTasks().remove(element);
                    element.setUserInfo(null);
                    taskInfoDAO.removeTaskInfo(element);
                }

    This code fragment trows an exception when invoking taskInfoDAO.removeTaskInfo(element):

    com.reuters.persistence.DAOException: deleted object would be re-saved by cascade (remove deleted object from associations): 9, of class: com.reuters.bean.TaskInfo wraps: [net.sf.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): 9, of class: com.reuters.bean.TaskInfo]
    at com.reuters.persistence.BaseDAO.removeObj(BaseDAO.java:42)
    ...


    Any suggestion? Thanks in advance.
  4. Hi, The problem here is , the child object may be linked with another parent tables. So when you try to delete you are getting this exception. Solution for this is: Check whether the child has linked with any other parents or not.I guess it must be linked with another parents. In your code. you are manually removing the child from parent by saying TaskInfo element = (TaskInfo) iter.next(); userInfo.getTasks().remove(element); element.setUserInfo(null); taskInfoDAO.removeTaskInfo(element); This is fine, you should do the same thing if the child is linked with anyother parent.Because when you say lazy="false", what happened it loads all the child records when parent loads. so when you try to remove the child since it is already loaded with another (may be if it is linked with another parent)parent it is not allowing to delete. or else you can also try this.check where are all you mapped your child class. in simply say lazy="true". try the difference. this time you no need to manually remove the child also by saying "userInfo.getTasks().remove(element);". Just call taskInfoDAO.removeTaskInfo(element); it will be deleted and it wont show this error also. Hope this works.
  5. try using cascade="delete"
  6. please introduce following changes to your user hbm: ... while removing logs collection, do this: UserBean userBean = (UserBean)session.load(UserBean.class,uid); LogBean log = logs.get(o); //from your code userBean.getLogs().remove(log); session.delete(log); session.flush(); hope it helps. Nabeel.