'Hibernate cascade save parent and children - parent key not found

I am using Spring, Hibernate and oracle for a project. The database schema was created manually by running sql script. Everything works fine until I encountered a problem with hibernate one-to-many bidirectional cascade save.

In the parent class (Product.java)

@OneToMany(mappedBy="product",
        fetch=FetchType.EAGER,
        cascade={CascadeType.ALL})
public Set<Picture> getPictures() {
        return pictures;
}

@Transient
public void addPicture(Picture picture) {
    picture.setProduct(this);
    pictures.add(picture);
}

In the child class (Picture.java)

@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="lse09lse06id")
public Product getProduct() {
        return product;
}

"lse09lse06id" is the foreign key column in the child entity table.

In my Controller class:

Product product = new Product();
.... (set properties of product)
Picture newPicture = new Picture();
.... (set properties of newPicture)
product.addPicture(newPicture);
productService.addProduct(product);

In my ProductService class:

@Override
@Transactional
public void addProduct(Product product) {
    productDAO.addProduct(product);
}

In my ProductDAO class:

@Override
public void addProduct(Product product) {
    product.setDateCreated(new Date());
    sessionFactory.getCurrentSession().save(product);
}

Exception thrown when the controller code is executed:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into lse09pictures (lse09content, lse09date_created, lse09date_deleted, lse09date_updated, lse09is_deleted, lse09lse06id, lse09id) values (?, ?, ?, ?, ?, ?, ?)]; constraint [CSSE3005GG.LSE09PICTURES_FK]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update

One of the nested exception thrown:

java.sql.BatchUpdateException: ORA-02291: integrity constraint (CSSE3005GG.LSE09PICTURES_FK) violated - parent key not found

Any help would be much appreciated. This problem is really nasty. Thank you!



Solution 1:[1]

Remove cascade from the @ManyToOne(cascade={CascadeType.ALL}). Hibernate gets confused by circular references.

Alternatively, save the Product instance (by explicitly calling session.save() on it) before the Picture instance.

Solution 2:[2]

Using the Hibernate Cascade classes

  • org.hibernate.annotations.Cascade
  • org.hibernate.annotations.CascadeType

Could you try to rewrite it like this:

@OneToMany(fetch=FetchType.EAGER,
@Cascade(value = { CascadeType.SAVE_UPDATE, CascadeType.PERSIST,
     CascadeType.MERGE })
public Set<Picture> getPictures() {
    return pictures;
}

And

@ManyToOne
@Cascade(value = { CascadeType.SAVE_UPDATE, CascadeType.PERSIST,
     CascadeType.MERGE })
@JoinColumn(name="lse09lse06id")
public Product getProduct() {
    return product;
}

After that, call to Hibernate.saveOrUpdate should do what you want.

Cyberax is right, circular references can be confusing for Hibernate. Plus, Cascading removal should be used with care - that is, why I only have used Save,Persist, and Merge.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Cyberax
Solution 2 Tobi