In JPA, to delete an entity, the entity itself must be managed. This means that the entity must be present in the persistence context. The application must have already loaded or accessed the entity and is now issuing a command to remove it.
Generally, this is not a problem given that most often the application will have caused it to become managed as part of determining that this was the object it wanted to remove.
1. JPA Delete Entity using EntityManager.remove()
If the application is accessing the persistent context using the EntityManager bean then we can use the ‘em.remove(entity)‘ to remove the entity from the database.
The remove() method performs the following when invoked on a managed entity:
- Moves the managed entity to the removed state. The entity gets deleted in the next flush.
- If the entity is detached, it needs to be merged first before removal.
- Throws IllegalArgumentException if the instance is not an entity or is a detached entity.
- The removal must be performed under a transaction, or else TransactionRequiredException is thrown.
- Be careful that after calling remove() the entity becomes a detached entity. So calling persist() will save the entity again in the database.
- To remove the related entities, those relationships must be marked as CascadeType.REMOVE.
In this example, we are first finding the ‘DepartmentEntity‘ using the find()
call, which returns a managed instance of DepartmentEntity. Then, we remove the entity using the remove()
call on the entity manager. It returns
@ContextConfiguration(locations = "classpath:application-context-test.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestRemoveEntity {
@PersistenceContext
private EntityManager manager;
@Test
@Transactional
@Rollback(true)
public void testRemoveDepartment(){
//Save test entity - generally done in setup method
DepartmentEntity department = new DepartmentEntity("Information Technology");
manager.persist(department);
Integer departmentId = department.getId();
//Find managed Entity reference
DepartmentEntity department = manager.find(DepartmentEntity.class, departmentId);
//Call remove method to remove the entity
if(department != null){
manager.remove(department);
}
//Verify
List<DepartmentEntity> departments = manager.createQuery("Select a From DepartmentEntity a",
DepartmentEntity.class).getResultList();
Assert.assertEquals(0, departments.size());
}
}
This remove() method will ensure that the department with the given ID, provided the ID is not null, is removed from the database.
It will return successfully whether the department exists or not. If the entity is null
, it simply does nothing.
2. JPA Delete Multiple Entities using JPQL or SQL Query
Another way to remove an entity is using JPQL (Java Persistence Query Language) in the below manner. It can help to delete multiple entities with a single statement and improve performance because they are executed directly on the database.
Always perform the deletion in a transaction. So we can roll back the transaction if something unexpected happens.
In the following example, the executeUpdate method performs the bulk delete operation and returns the number of entities deleted. The syntax for the JPQL delete query is similar to SQL but operates on entity objects and their fields.
String jpql = "DELETE FROM DEPARTMENT WHERE ID = :departmentId";
int deletedCount = em.createQuery(jpql)
.setParameter("departmentId", departmentId)
.executeUpdate();
In fact, in this way, you can remove multiple rows in a single query, which is not possible using EntityManager.remove() method.
String jpql = "DELETE FROM DEPARTMENT WHERE ID IN :ids";
int deletedCount = em.createQuery(jpql)
.setParameter("ids", ids)
.executeUpdate();
It is worth mentioning that we can also use the native SQL queries also, in place of JPQL, as both are pretty similar in syntax. We need to use the createNativeQuery() when using the SQL queries.
In the following code snippet, we have rewritten the JPQL example as a native SQL query example.
String sql = "DELETE FROM DEPARTMENT WHERE ID = " + departmentId;
int deletedCount = em.createNativeQuery(sql)
.setParameter("departmentId", departmentId)
.executeUpdate();
3. Type-safe Way to Delete Entity using CriteriaDelete
Since JPA 2.1, the CriteriaBuilder API introduced CriteriaDelete class to generate the DELETE operation. It helps in creating the DELETE queries similar to how we would create SELECT queries with the Criteria API.
- As with other methods, always run the query in a transaction.
- This method also returns the number of entities deleted.
In the following example, we are deleting all the departments whose ID is greater than the specified parameter.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaDelete<Person> delete = cb.createCriteriaDelete(Person.class);
Root<DepartmentEntity> root = delete.from(DepartmentEntity.class);
delete.where(cb.greaterThan(root.get("id"), id));
int deletedCount = em.createQuery(delete).executeUpdate();
System.out.println(deletedCount + " depertments were deleted.");
Happy Learning !!
Comments