Delete JPA Entity

In many situations you may want to delete an existing entity object from the database. For this, you can use the remove() method provided by EntityManager. This may also delete associated entities as a result of a cascade operation. Embedded objects that are contained in the entity object are also deleted. Please remember, you must remove an entity within an active transaction otherwise you will get a TransactionRequiredException.

Delete using remove() method

Let’s consider we have a State and City entity and they have a one-to-many relationship.

@Entity
@Table(name = "STATE", schema = "DEMO")
public class State {
    @Id
    @Column(name = "STATE_ID")
    private long stateId;

    @OneToMany(mappedBy = "state", cascade = CascadeType.ALL)
    private Set<City> cities = new HashSet<City>();
}
@Entity
@Table(name = "CITY", schema = "DEMO")
public class City {
    @Id
    @Column(name = "CITY_ID")
    private long cityId;
    
    @ManyToOne
    @JoinColumn(name = "STATE_ID")
    private State state;
}

Let’s assume, we have the following data in the database. The STATE_ID in CITY table is used as a foreign key.

Now, try to retrieve the state object with id 1 and remove it using the remove() method.

State state = entityManager.find(State.class, 1L);
entityManager.remove(state)

Once the transaction is committed, both state and corresponding cities will be deleted from the database.

Delete using query

Let’s try to delete the state using a JPQL query.

Query query = entityManager.createQuery("delete from State s where s.stateId = :id");
query.setParameter("id", 1L);
query.executeUpdate();

You will get following exception –

java.sql.SQLIntegrityConstraintViolationException: ORA-02292: integrity constraint violated - child record found

The reason is, JPQL doesn’t care about cascade type. It will do exactly what you have instructed it to do. As the state id is being used as a foreign key in the CITY table, you should delete the cities first, then state.

Query query1 = entityManager.createQuery("delete from State s where s.stateId = :id");
Query query2 = entityManager.createQuery("delete from City c where c.state.stateId = :id");
		
query1.setParameter("id", 1L);
query2.setParameter("id", 1L);
		
query2.executeUpdate();
query1.executeUpdate();

This will work just fine.

Orphan removal

Rather than removing the entire state object, let’s try to remove only one City from the state.

State state = entityManager.find(State.class, 1L);
Collection<City> cities = state.getCities();
City oneCity = null;

for (City city : cities) {
    if ("Mumbai".equalsIgnoreCase(city.getCityName())) {
        oneCity = city;
        break;
    }
}

state.getCities().remove(oneCity);

You may expect, the city with the name Mumbai will be removed from the database. Surprisingly that will not happen.

The reason is, when you remove the city from the city collection, you basically disconnected the object from the collection. Hibernate does not treat this same as remove operation.

The solution is, you have to use the orphanRemoval element of the @OneToOne or @OneToMany annotations. The main purpose of this element is to delete orphaned (disconnected) entities from the database. When an entity is no longer attached to its parent, it is called an orphan. 

So let’s include the orphanRemoval element.

@Entity
@Table(name = "STATE", schema = "DEMO")
public class State {
    @Id
    @Column(name = "STATE_ID")
    private long stateId;

    @OneToMany(mappedBy = "state", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<City> cities = new HashSet<City>();
}

Now if you try to remove one city from the state, it will work just fine.

orphanRemoval=true includes the behavior of cascade=CascadeType.REMOVE. So if you don’t specify the cascade type as REMOVE or ALL, remove operation will work just fine.

That’s it for now. Hope you have enjoyed this tutorial. If you have any doubt, please ask in the comment section. I will try to answer that as soon as possible. Till then, bye bye.