Results 1 to 4 of 4

Thread: Spring, Hibernate, cascade not working...

  1. #1

    Default Spring, Hibernate, cascade not working...

    This is a repost of a post from yesterday. But I've enclosed the code in tags to make it more readable. Sorry for the annoyance.

    I'm using Spring 2, Hibernate 3, and JPA annotations. When I write out a parent class where there is a parent child relationship defined in the database and by the annotations, the cascade does not happen. i.e. When I write the parent, it's children are not written.

    Here's the springs beans I'm using:

    Code:
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName"><value>com.mysql.jdbc.Drive r</value></property>
    <property name="url"><value>jdbc:mysql://${mysql.host}:${mysql.port}/dandelion</value></property>
    <!-- <property name="url"><value>jdbc:mysql://${mysql.host}:${mysql.port}/dandelion</value></property> -->
    <property name="username"><value>${mysql.user}</value></property>
    <property name="password"><value>${mysql.password}</value></property>
    </bean>
    
    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotati on.AnnotationSessionFactoryBean">
    <property name="dataSource">
    <ref bean="dataSource"/>
    </property>
    <property name="annotatedClasses">
    <list>
    <value>com.adobe.dandelion.dao.model.Parent</value>
    <value>com.adobe.dandelion.dao.model.Child</value>
    </list>
    </property>
    <property name="annotatedPackages">
    <list>
    <value>com.adobe.dandelion.dao.model</value>
    </list>
    </property>
    <property name="hibernateProperties">
    <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQ LDialect</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.format_sql">true</prop>
    <prop key="hibernate.search.autoregister_listeners">fals e</prop>
    </props>
    </property>
    </bean>
    
    <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.Hibernat eTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <bean id="childDao" class="com.adobe.dandelion.dao.ChildDaoHibernate">
    <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <bean id="parentDao" class="com.adobe.dandelion.dao.ParentDaoHibernate" >
    <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    Here's my Parent class:

    Code:
    package com.adobe.dandelion.dao.model;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;
    
    @Entity
    @Table(name="parents")
    
    public class Parent {
    private Integer id;
    private Set<Child> childs = new HashSet();
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    
    public Integer getId() {
    return id;
    }
    public void setId(Integer id) {
    this.id = id;
    }
    
    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, 
    mappedBy = "parent",
    fetch = FetchType.LAZY)
    
    public Set<Child> getChilds() {
    return childs;
    }
    
    public void setChilds(Set<Child> childs) {
    this.childs = childs;
    }
    
    public void addChild(Child child) {
    if (child == null)
    throw new IllegalArgumentException("Null child");
    if (child.getParent() != null)
    child.getParent().getChilds().remove(child);
    child.setParent(this);
    childs.add(child);
    }
    
    public void removeChild(Child child)
    {
    if (child == null)
    throw new IllegalArgumentException("Null child");
    childs.remove(child);
    child.setParent(null);
    }
    }
    Here's the Child class:

    Code:
    package com.adobe.dandelion.dao.model;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.ManyToOne;
    import javax.persistence.Table;
    
    @Entity
    @Table(name = "childs")
    
    public class Child {
    private Integer id = null;
    private Parent parent = null;
    
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    
    public Integer getId() {
    return id;
    }
    public void setId(Integer id) {
    this.id = id;
    }
    
    @ManyToOne
    @JoinColumn(name = "parent", nullable = false)
    
    public Parent getParent() {
    return parent;
    }
    
    public void setParent(Parent parent) {
    this.parent = parent;
    }	
    }
    The Dao for each extend HibernateDaoSupport and each have a method for saving and updating that looks like this:

    Code:
    public void saveOrUpdate( T entity )
    {
    getHibernateTemplate().saveOrUpdate(entity);
    }
    The code that creates a Parent and Child and saves the parent looks like this:

    Code:
    Parent parent = new Parent();
    Child child = new Child();
    parent.addChild(child);
    
    parentDao.saveOrUpdate(parent);
    If my understanding is correct, since I marked the classes with annotations specifying cascading inserts and updates, the child should have been written. When I look in the database it is not there.

    One thing that I wonder about is whether the JPA annotations can be used with hibernate sessions, or do you have to use the JPA entity manager? I also don't understand which Spring is using under the covers in my case.

    Any ideas?

  2. #2

    Default cascade on @ManyToOne

    I found the problem. I needed to put the cascade attribute on the ManyToOne annotation of the child, not the OneToMany annotation of the parent. Maybe I need both. Looking into that. Here's the corrected snippet of code for the child.

    Code:
    	@ManyToOne(cascade = { CascadeType.ALL })
    	@JoinColumn(name = "parent", nullable = false)
    	public Parent getParent() {
    		return parent;
    	}
    
    	public void setParent(Parent parent) {
    		this.parent = parent;
    	}

  3. #3

    Default Should work on the OneToMany annotation

    I checked the book "Java Persistence with Hibernate". In their example of creating parent child relationships, they show the cascade attribute only on the OneToMany side (the parent) of the relationship, so my original code should work. I don't know why it requires the annotation on the ManyToOne side.

  4. #4

    Default Move annotations from getters to fields fixed problem

    I moved all the annotations for both classes from the setters/getters to the private field declarations. I could then remove the cascading attribute from the child class. When I saved the parent both relationships were saved. This is probably a novice error.

    Lesson learned: Put JPA/Hibernate annotations on the private fields, not the setters/getters.

    Thanks,
    Michael-

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •