2

We installed our package in a client org that does a callout from a trigger to sync with their system. The client has classes that set savepoints causing errors with the callouts and I want to make sure that if we remove some of the savepoints that the client doesn't lose anything.

I want to say that they won't actually lose anything by removing the savepoints, but I would appreciate some confirmation so that I don't mistakenly give them misinformation.

Savepoint sp = Database.setSavepoint();
if(!isSaved){
    try{
        //Setting fields
        ...

        List<Contracted_Equipment__c> addProducts = new List<Contracted_Equipment__c>();
        List<Contracted_Equipment__c> deleteProducts = new List<Contracted_Equipment__c>();
        for(wEquipment w : equipmentList){          
            if(w.selected){                 
                if(!isFirstInstallation){
                    theOpportunity.Installation__c = w.equipmentRecord.Installation__c; 
                    isFirstInstallation = true;
                }                                
                if(!w.originallySelected){                  
                    Contracted_Equipment__c ce = new Contracted_Equipment__c();
                    ce.Opportunity__c = theOpportunity.Id;                       
                    ce.Equipment__c = w.equipmentRecord.Id;
                    addProducts.add(ce);
                }
            }
            else{               
                if(w.originallySelected)
                    deleteProducts.add(new Contracted_Equipment__c(Id=w.contractedEquipmentId));
            }
        }
        if(addProducts.size()>0)
            insert addProducts;
        if(deleteProducts.size()>0)
            delete deleteProducts;

        if(oppoOriginalInstallation != theOpportunity.Installation__c){    
            update theOpportunity;
        }  

        isSaved = true; 
        // Check is user on ContractedEquipmentsEdit or ContractedEquipmentsOpportunityEdit and forward user to next page or show result
        if(getVFPageName() != 'ContractedEquipmentsOpportunityEdit'){
            ref = new Pagereference('/'+theOpportunity.Id);     
        } 
    }catch(Exception e){        
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Saving failed: '+e.getMessage()));
        Database.rollback(sp);
        isSaved = false;
        return null;
    }
}
3

This Savepoint absolutely does serve a purpose. Basically, you can boil the structure down to:

Savepoint sp = Database.setSavepoint();
try
{
    insert someRecords;
    delete someOtherRecords;
    update anotherRecord;
}
catch (Exception pokemon)
{
    Database.rollback(sp);
}

So, imagine if something goes wrong on that third DML Operation (update anotherRecord). With the Savepoint, they all work together as a transaction. Without it, the other two DML Operations in your transaction succeed even if the third fails.

The only way the code will behave the same after removing the Savepoint is the case where you get a failure before or during insert someRecords.

Which Operation Fails?     Use Savepoint?      insert?      update?      delete?
                insert                yes           no           no           no
                update                yes           no           no           no
                delete                yes           no           no           no

                insert                 no           no           no           no
                update                 no          yes           no           no
                delete                 no          yes          yes           no
| improve this answer | |
  • Thank you! For some reason I had thought that if one of those would fail, it would completely roll the transaction back inside the entire try/catch. I assumed it was if you had multiple try/catches with different dmls in each of those – dphil Nov 14 '16 at 17:08
  • Hmmm any suggestions on how to keep this functionality if there is a call out on the Opportunity trigger firing? – dphil Nov 14 '16 at 17:10
  • @dphil Have you considered asynchronous processing? Using @future or Queueable might help. – Adrian Larson Nov 14 '16 at 17:13
  • I'll check to see where they are feasible to do, and hopefully it can be at that point. I know we are doing some future already for certain things so I need to make sure that doesn't somehow cause more issues. Thanks again. – dphil Nov 14 '16 at 17:20
  • 1
    Yeah once you start delving into async it can get a little tricky, Appleman has a whole chapter about it in his book (probably the most worthwhile chapter to read). – Adrian Larson Nov 14 '16 at 17:24

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.