1

I have a Apex Batch job that "cleans" object permissions on permission sets automatically based on some rules.

Essentially in each batch execution I am deleting all ObjectPermission records to a specific permission set and insert all "allowed" ObjectPermission records right after. Since I want to avoid code failures due to a Master-Detail relationship (FIELD_INTEGRITY_EXCEPTION, trying to remove access to the parent object while the child object is still accessible) the code does multiple deletion attempts based on the Database.delete method. Here is the specific code snippet:

Id permissionSetId = '0PS0Y0000007cTX' // for this example
List<ObjectPermissions> objPerms = [SELECT Id 
                                    FROM ObjectPermissions
                                    WHERE ParentId = :permissionSetId];
List<SObject> tmpRecords = records.clone();

while( !tmpRecords.isEmpty()) {
    List<Database.DeleteResult> dmlResults = Database.delete(tmpRecords, false);

    objPerms = tmpRecords.clone();
    tmpRecords.clear();

    for(Integer i=0, size = objPerms.size(); i<size; i++) {
        if( !r.isSuccess()){
            SObject failedRecord = objPerms.get(i);

            tmpRecords.add(failedRecord);
        }
    }
}

If the code is executed within one batch execution the transaction fails because of too many retries (150 DML Statement limit). Specific observed behavior was:

  • First Iteration: Started with 130 records, could not delete 4
  • Second Iteration: Started with 4 records, could not delete 1
  • Third to 150th Iteration: Started with records, could not delete 1 until DML Statement Limit Exception.

(Database.Error[getFields=();getMessage=Permission Read CHILD_OBJECT depends on permission(s): Read PARENT_OBJECT;getStatusCode=FIELD_INTEGRITY_EXCEPTION;])

If I execute the delete operations in two separate anonymous apex scripts the deletion succeeds.

  • First Iteration: Started with 130 records, could not delete 4
  • Second Iteration: Started with 4 records, could not delete 0

here is the code:

 Id permissionSetId = '0PS0Y0000007cTX' // for this example
List<ObjectPermissions> objPerms = [SELECT SObjectType, PermissionsRead, PermissionsCreate, PermissionsEdit, PermissionsDelete, PermissionsViewAllRecords, PermissionsModifyAllRecords 
                                    FROM ObjectPermissions
                                    WHERE ParentId = :permissionSetId];

System.debug(objPerms.size());

List<Database.DeleteResult> results = Database.delete(objPerms, false);

for(Database.DeleteResult r : results) {
    if(!r.isSuccess()){
        System.debug(r.getErrors());
    }
}

Any ideas if SF changed sth in the deletion process within Apex Batch?

  • i might approach this by chaining batchables, passing the ids (in finish() of the failed-to-delete objects to the constructor of the next batchable. The same class can be used for all. This allows for 1,2,3,4, ... passes. You could stop the chaining when execution i deletes nothing given the input – cropredy Dec 10 '19 at 18:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.