This Hibernate basics tutorial shows you three different ways to remove an entity from the datastore. Suppose that we have the following entity relationship (one-to-many):

one-to-many entity relationship

A category can contain one or many products. The following MySQL script creates the database and the two tables:

create database stockdb;
use stockdb;

CREATE TABLE `category` (
  `category_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`category_id`)
);

CREATE TABLE `product` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `description` varchar(512) NOT NULL,
  `price` float NOT NULL,
  `category_id` int(11) NOT NULL,
  PRIMARY KEY (`product_id`),
  KEY `fk_category` (`category_id`),
  CONSTRAINT `fk_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`category_id`)
);
As normal, we use JPA annotations to annotate the model classes:

Category.java:

package net.codejava.hibernate;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;


@Entity
@Table(name = "CATEGORY")
public class Category {

	private long id;
	private String name;

	private Set<Product> products;

	public Category() {
	}

	public Category(String name) {
		this.name = name;
	}

	@Id
	@Column(name = "CATEGORY_ID")
	@GeneratedValue
	public long getId() {
		return id;
	}

	@OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
	public Set<Product> getProducts() {
		return products;
	}

	// other getters and setters...
}
 

Product.java:

package net.codejava.hibernate;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "PRODUCT")
public class Product {
	private long id;
	private String name;
	private String description;
	private float price;

	private Category category;

	public Product() {
	}

	public Product(String name, String description, float price,
			Category category) {
		this.name = name;
		this.description = description;
		this.price = price;
		this.category = category;
	}

	@Id
	@Column(name = "PRODUCT_ID")
	@GeneratedValue
	public long getId() {
		return id;
	}

	@ManyToOne
	@JoinColumn(name = "CATEGORY_ID")
	public Category getCategory() {
		return category;
	}

	// other getters and setters...
}
We need to delete an individual product or a category with associated products. Let’s see how to accomplish this requirement using Hibernate APIs.

 

1. Deleting a transient instance



The Session.delete(Object) method allows us to remove a transient instance of the entity with an identifier associated with existing persistent state. A transient instance is the one which does not associate with the session. For example, the following statements delete a product whose identifier equals to 37:

Product product = new Product();
product.setId(37);
session.delete(product);
Hibernate issues this query:

Hibernate: delete from PRODUCT where PRODUCT_ID=?
This way is simple and straightforward, because we don’t have to load a persistent instance from the datastore before deleting it. However, its drawback is that it doesn’t remove the associated instances, even an appropriate cascade type is specified in the class mappings/annotations. Consider the following statements:

Category cat = new Category();
cat.setId(17);
session.delete(cat);
If the category (ID=17) is associated with some products (in the datastore), the code will throws a ConstraintViolationException at runtime because Hibernate attempts to remove only the category while it is still referenced by some products. We would see an error message like this:

ERROR: Cannot delete or update a parent row: a foreign key constraint fails
(`stockdb`.`product`, CONSTRAINT `fk_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`category_id`))
How to solve this problem is covered next.

 

2. Deleting a persistent instance

In this way, we load a persistent instance using the Session.load(Class, ID) method before deleting it. For example, the following code snippet solves the above problem of deleting a category with associated products:

Serializable id = new Long(17);
Object persistentInstance = session.load(Category.class, id);
if (persistentInstance != null) {
	session.delete(persistentInstance);
}
Hibernate issues these queries:

Hibernate: select category0_.CATEGORY_ID as CATEGORY1_0_0_, category0_.name as ...
Hibernate: select products0_.CATEGORY_ID as CATEGORY5_0_1_, products0_.PRODUCT_ID ...
Hibernate: delete from PRODUCT where PRODUCT_ID=?
Hibernate: delete from PRODUCT where PRODUCT_ID=?
Hibernate: delete from CATEGORY where CATEGORY_ID=?
Using this technique, we tend to write a utility method like this:

private boolean deleteById(Class<?> type, Serializable id) {
	Object persistentInstance = session.load(type, id);
	if (persistentInstance != null) {
		session.delete(persistentInstance);
		return true;
	}
	return false;
}
Usage example:

boolean result = deleteById(Product.class, new Long(41));
  

3. Using Hibernate Query Language (HQL)

In this way, we use Hibernate Query Language (HQL) to delete entities with more flexibility, such as removing products whose prices are greater than a specified amount. For example:

Query query = session.createQuery("delete Product where price > :maxPrice");
query.setParameter("maxPrice", new Float(1000f));

int result = query.executeUpdate();

if (result > 0) {
	System.out.println("Expensive products was removed");
}
Hibernate issues this query:

Hibernate: delete from PRODUCT where price>?
As you can see, Hibernate issues only one DELETE query, in contrast with the first two approaches in which Hibernate issues a SELECT query first, then to DELETE. However, this approach doesn’t remove associated instances. Consider the following example:

Query query = session.createQuery("delete Category where id = :ID");
query.setParameter("ID", new Long(18));

int result = query.executeUpdate();
A ConstraintViolationException will be thrown at runtime if the category associates with some products. In this case, we have to write two queries: the first is to remove the products and the second is to remove the category.

So far we have looked at the three different ways of deleting entities from the datastore using Hibernate APIs. Each has its own pros and cons, so it’s up to you to decide which best suites your need.

 

Other Hibernate Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment

   


Comments 

#12Nam2022-05-23 21:56
To Shweta: to do so, you need to do 2 things:
- Set cascade type on category side is NONE.
- alter the table product to accept null in category_id column.
Note that doing so you will break the foreign key constraint, which is not a good design.
Quote
#11Shweta2022-05-23 08:56
Hi what needs to do if we need to delete only category but on deleting category product should not deleted. Do we have any provosion to only nullify the category refrence in Product table on deleting the category.
Quote
#10Nam2022-01-02 20:10
Hi Franck,
For soft deletion, you add a new boolean field "deleted" to an entity class. And when an item of the entity is moved to trash, set deleted=true.
Quote
#9Franck2022-01-01 07:49
Thanks Nam, this used to be a nightmare for me but now i understand, but what about Soft Delete, some people tend to use this approach too to solve this issue!
Quote
#8Muskan Agarwal2020-08-02 10:42
In the second option
2. Deleting a persistent instance
I think you should use "get" method instead of "Load" because load will give an exception not null if that particular key is not in table while get will give you null.
Quote