'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 |