Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

EclipseLink/Examples/JPA/SoftDelete

< EclipseLink‎ | Examples‎ | JPA
Revision as of 03:18, 8 August 2013 by Omidatbiz.gmail.com (Talk | contribs) (Using QueryRedirectors to change delete to perform an update)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Some applications prefer to archive deleted objects instead of deleting them. This can be desired for auditing, or backup purposes. This is sometimes referred to as "soft" deletes, in that rows are never deleted, just marked as delete through a status column in the table.

EclipseLink supports soft deletes through two mechanisms, the @AdditionalCriteria annotation (or XML) and the DescriptorQueryManager API.

To implement soft deletes you need a status column in your table, in this example we will use STATUS. You can define an attribute in your entity to map to the status, or leave it as un-mapped if desired. If un-mapped, you will need to add a QueryKey for it to query on it through JPQL.

Next, you will need to override the delete operation for your entity to instead update the status field to 'deleted'. This can be done through using a DescriptorCustomizer and using the DescriptorQueryManager setDeleteSQLString() API.

Finally, to avoid having deleted object returned on queries, you can configure an @AdditionalCriteria to exclude the values.

Employee entity using soft deletes

@Entity
@AdditionalCriteria("this.status <> 'deleted'")
public class Employee {
  @Id
  @Column(name="EMP_ID")
  private long id;
  @Basic
  private String status; // This is optional, as a query-key could also be used.
}

Using DescriptorCustomizer to change delete to perform an update

public class MyCustomizer implements DescriptorCustomizer {
  public void customize(ClassDescriptor descriptor) {
    descriptor.getQueryManager().setDeleteSQLString("Update EMPLOYEE set STATUS = 'deleted' where EMP_ID = #EMP_ID");
    // Optionally add a query key for status.
    descriptor.addDirectQueryKey("status", "STATUS");
  }
}

Using QueryRedirectors to change delete to perform an update

A different option to intercept the deletion is to use a QueryRedirector to redirect the delete operation. This is more complex, but can give you more control to do something different. The redirector must be set on the descriptor's delete query.

public class CustomDeleteRedirector implements QueryRedirector
{
 
    @Override
    public Object invokeQuery(DatabaseQuery query, Record arguments, Session session)
    {
        ClassDescriptor descriptor = session.getDescriptor(query.getReferenceClass());
        DeleteObjectQuery deleteObjectQuery = (DeleteObjectQuery) query;
        EMPLOYEE emp = (EMPLOYEE) deleteObjectQuery.getObject();
        emp.setStatus("deleted");
        UpdateObjectQuery updateObjectQuery = new UpdateObjectQuery(emp);
        descriptor.addDirectQueryKey("status", "STATUS");
        updateObjectQuery.setDescriptor(descriptor);
        deleteObjectQuery.setDescriptor(updateObjectQuery.getDescriptor());
        return updateObjectQuery.execute((AbstractSession) session, (AbstractRecord) arguments);        
    }
 
}

Back to the top