1. Introduction
The Logical Delete plugin provides support for soft deleting records.
A logical or soft deletion, is one that doesn’t actually delete the record from persistent storage, but instead marks the record as deleted.
Marking the record as deleted has the benefit of maintaining the ability to retrieve the record if necessary.
Essentially, the plugin offers a mechanism to hide records from retrieval. This is useful for retaining records without having it clutter the current set of active data.
2. Installation
2.1. Adding the Plugin to Your Grails Application
To add this plugin to your Grails application, include the following dependency in the dependencies block of
the build.gradle file:
implementation 'org.grails.plugins:grails-logical-delete:3.0.0-SNAPSHOT'
2.2. Snapshot Builds
You can also use snapshot builds, as they are published to the Grails Artifactory Repository.
3. Usage
3.1. The LogicalDelete Trait
This plugin provides the LogicalDelete trait, which any Grails domain class can implement to enable soft deletes.
The trait adds a persistent boolean property named deleted to the domain class.
When deleted is set to true, the entity is considered logically deleted and will be
excluded from query results by default.
import grails.logical.delete.LogicalDelete
class Person implements LogicalDelete<Person> {
String userName
static mapping = {
// the deleted property may be configured
// like any other persistent property...
deleted(column: 'delFlag')
}
}
3.2. Soft Deleting Entities
Deleting an entity that implements the LogicalDelete trait
is as simple as calling the delete() method. This sets the deleted property to true, causing the record
to be logically deleted — meaning it will be excluded from query results by default.
Person p = new Person(userName: 'Nirav').save()
p.delete()
To restore (or undelete) the object, call the undelete() method:
p.undelete()
If you want to physically delete the record from persistent storage, pass the hard: true argument to the delete() method:
p.delete(hard: true)
3.3. Queries
Most queries automatically exclude logically deleted records from their results by default.
| Hibernate Criteria and HQL queries are NOT supported by this plugin. |
For example, a dynamic finder query written as:
results = Person.findAll {
userName == 'Robert'
}
is executed as if it had been written like this:
results = Person.findAll {
userName == 'Robert'
deleted == false
}
If you need to include logically deleted records in query results, wrap your query in a call to withDeleted,
as shown below. Any query can be wrapped with the withDeleted closure.
results = Person.withDeleted { Person.findAll() } as List<Person>
The plugin supports a variety of query types in addition to dynamic finders.
Examples are shown below:
3.3.1. Criteria Query
def criteria = Person.createCriteria()
def results = criteria.list {
or {
eq('userName', 'Ben')
eq('userName', 'Nirav')
}
}
3.3.2. Detached Criteria Query
def results = Person.where {
userName == 'Ben' || userName == 'Nirav'
}.list()
3.3.3. GORM methods
The standard GormEntity<D> methods — such as get, load, proxy, and read — are also supported.
3.3.4. GORM Data Services
GORM Data Services are supported. See the example below for an example.
3.4. WithDeleted Annotation
The @WithDeleted annotation allows you to mark a method so that queries executed within it
include logically deleted records. It serves as an alternative to using the withDeleted closure.
This is particularly useful when working with GORM Data Services or other classes that function as Data Access Objects (DAOs).
@Service(Person)
interface PeopleDataService {
List<Person> listPeople()
@WithDeleted
List<Person> listPeopleWithDeleted()
void delete(Serializable id)
}
4. Implementation Details
This section provides a brief overview of the internal implementation of the Grails Logical Delete plugin.
The LogicalDelete trait defines the deleted property
and overrides core persistence methods to implement soft deletion and query filtering behavior.
The PreQueryListener listens for query events and modifies the query to automatically exclude logically deleted records.
The project’s Spock tests serve as a useful reference for examples and usage patterns of the plugin’s API.
5. API Documentation
API documentation may be found here.