8.4 Deleting Instances

You can call one of the following PersistenceManager methods to delete one or more persistent instances from the datastore:

void deletePersistent(Object obj);
void deletePersistentAll(Object[] objs);
void deletePersistentAll(Collection objs);

They must be called in the context of an active transaction, or a JDOUserException is thrown. The representation of the instance in the datastore is deleted when it is flushed to the datastore (via commit( ) or evict( )). Chapter 13 covers the evict( ) method. These methods have no effect on instance parameters that are already deleted in the transaction. They throw a JDOUserException if a parameter is transient or managed by a different PersistenceManager.

The following application is used to delete a customer from the datastore. This includes deleting all the customer's transactions. Line [1] accesses the Customer instance. If line [2] determines that Rental instances are still associated with the Customer instance, the application prints an error message and returns without removing any data. Otherwise, it deletes the Customer instance and its associated Address and Transaction instances.

package com.mediamania.store;

import java.util.Set;
import java.util.List;
import com.mediamania.MediaManiaApp;

public class DeleteCustomer extends MediaManiaApp {
    private String  lastName;
    private String  firstName;
    
    public DeleteCustomer(String fname, String lname) {
        lastName = lname;
        firstName = fname;
    }
    public static void main(String[] args) {
        DeleteCustomer deleteCustomer = new DeleteCustomer(args[0], args[1]);
        deleteCustomer.executeTransaction(  );
    }   
    public void execute(  ) {
        Customer customer = StoreQueries.getCustomer(pm, firstName, lastName);     [1]
        Set rentals = customer.getRentals(  );
        if (!rentals.isEmpty(  )) {     [2]
            System.err.print(firstName); System.err.print(" ");
            System.err.print(lastName);
            System.err.print(" cannot be deleted until current rentals ");
            System.err.println("are returned");
            return;
        }
        List transactions = customer.getTransactionHistory(  );
        Address address = customer.getAddress(  );
        pm.deletePersistent(address);
        pm.deletePersistentAll(transactions);
        pm.deletePersistent(customer);
    }    
}

Some datastores and JDO implementations support integrity constraintssimilar to referential integrity constraintsthat could prevent the deletion of an instance. If your application uses these non-JDO facilities, it is implementation-defined whether an exception is thrown at commit or the delete operation is simply ignored. Explicit support for automatic relationship maintenance, delete propagation, and referential integrity constraints are being considered as a possible feature in the next release of JDO.

The behavior of deletePersistent( ) and deletePersistentAll( ) is not exactly the inverse of makePersistent( ) and makePersistentAll( ), due to the transitive nature of persistence-by-reachability, which is not used when you delete instances. You need to call deletePersistent( ) or deletePersistentAll( ) explicitly for all instances that need to be deleted. Any instances that are referenced by the deletePersistent( ) and deletePersistentAll( ) parameters are not deleted, unless they are also parameters to these methods.

8.4.1 Delete Propagation

Some implementations support delete propagation. On a persistent class basis, you would indicate which references and collections should be traversed to establish a set of related instances to be deleted. When the application deletes an instance of the class, the JDO implementation automatically deletes the specified set of related instances. This capability is similar to the persistence-by-reachability algorithm, except it performs the inverse operation.

This relies on implementation-specific facilities that are not covered by the JDO specification. Some implementations allow you to specify this behavior in the metadata and invoke it automatically when the application calls deletePersistent( ) or deletePersistentAll( ). If you want your application to be portable, you should use deletePersistent( ) or deletePersistentAll( ) for all deletions from the datastore, and you should not depend on implementation-specific reachability algorithms that automatically delete related instances.

A portable approach for delete propagation is to use the jdoPreDelete( ) callback, defined in the JDO InstanceCallbacks interface. If your persistent class has declared that it implements InstanceCallbacks, this method is called during the execution of deletePersistent( ):

public void jdoPreDelete(  );

This method is useful when you have a composite-aggregation association, where the related instances are considered existence-dependent components of the composite object. The deletion semantics of the composite aggregate can be defined by deleting the dependent instances in this method. This method can reference and use any of the fields in the class. But when the method completes, you cannot access any of the deleted instance's fields, or a JDOUserException is thrown.