Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/JPA/SoftDelete"

(Using QueryRedirectors to change delete to perform an update)
(Using QueryRedirectors to change delete to perform an update)
 
Line 55: Line 55:
 
         UpdateObjectQuery updateObjectQuery = new UpdateObjectQuery(emp);
 
         UpdateObjectQuery updateObjectQuery = new UpdateObjectQuery(emp);
 
         descriptor.addDirectQueryKey("status", "STATUS");
 
         descriptor.addDirectQueryKey("status", "STATUS");
        updateObjectQuery.setDescriptor(descriptor);
 
 
         updateObjectQuery.setDescriptor(descriptor);
 
         updateObjectQuery.setDescriptor(descriptor);
 
         deleteObjectQuery.setDescriptor(updateObjectQuery.getDescriptor());
 
         deleteObjectQuery.setDescriptor(updateObjectQuery.getDescriptor());

Latest revision as of 03:18, 8 August 2013

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);        
    }
 
}