[SalesForce] How to perform Callout and DML operation simultaneously

I'm facing a issue while doing a callout. I have tried from my side, but unable to wave it out.

1) Create a custom setting with name – FolderDetails . //Done
2) Have the custom settings store Object name and FolderID. //Done
3)Create a method which takes the object type and check in custom setting if the object type is existing , if existing then return true and create only subfolder taking the existing folder id as parent id for subfolder else create the Object type folder .

I have created a method createFirstFolder() which will create a folder in BOX server and will generate FolderID. I’m able to get the objecttype and folderID. And inserting into the custom settings.

Once Custom Settings updated, I’m calling a second method createSecondFolder().

But I’m getting the error message i.e.

You have uncommitted work pending. Please commit or rollback before
calling out issue workaround in salesforce

I know that you can'nt do the DMl operaion before callout.

Anyone can please guide me with another approach.

//Create my first Folder
    public PageReference createFirstFolder(){
             String objecttype = IdVar.getSobjectType().getDescribe().getName();
             System.debug('objecttype  :'+objecttype);
             APIReqRespWrapperRudra.BoxFolder boxFolderDetails=new APIReqRespWrapperRudra.BoxFolder();
             APIReqRespWrapperRudra.BoxFolder createBox=new APIReqRespWrapperRudra.BoxFolder();
             APIReqRespWrapperRudra.cls_parent  parentBox=new APIReqRespWrapperRudra.cls_parent();
             parentBox.id = '0';
             createBox.name=objecttype;
             createBox.parent=parentBox;
             boxFolderDetails= BoxIntegrationUtilities_Folder.createFolderInBox(createBox,'4yO2bWC19KUPeFdPNi36BAWRyjwfdLVj');
             System.debug('Folder ID : '+boxFolderDetails.id);
             System.debug('Folder Name : '+boxFolderDetails.name);
             UpdateCustomSettings(boxFolderDetails.name,boxFolderDetails.id); //Update custom settings with objecttype name and folderid
             createSecondFolder(boxFolderDetails.id,boxFolderDetails.name,objecttype); //It will call to another method to create a Inner folder within the folder just created.
             return null;
          }

private void UpdateCustomSettings(String ObjectName, String folderid){
        System.debug('++'+ObjectName);
        System.debug('++'+folderid);
        FolderDetails__c myCustomObject = new FolderDetails__c (Name = ObjectName, FolderId__c = folderid);
        insert myCustomObject ; 
        System.debug('!!!'+myCustomObject);  
     } 

public PageReference createSecondFolder(String folderId,String foldername, String objecttype){
         //String objecttype = IdVar.getSobjectType().getDescribe().getName();
         System.debug('objecttype  :'+objecttype);
         List<FolderDetails__c> mcs = FolderDetails__c.getall().values();
         System.debug('MCS Size :'+mcs.size());
         for(Integer i=0;i<mcs.size();i++){
             if(objecttype == mcs[i].Name){
                 APIReqRespWrapperRudra.BoxFolder boxFolderDetails=new APIReqRespWrapperRudra.BoxFolder();
                 APIReqRespWrapperRudra.BoxFolder createBox=new APIReqRespWrapperRudra.BoxFolder();
                 APIReqRespWrapperRudra.cls_parent  parentBox=new APIReqRespWrapperRudra.cls_parent();
                 parentBox.id = folderId;
                 createBox.name=foldername + +' '+ System.Now() +'-';
                 createBox.parent=parentBox;


                 boxFolderDetails= BoxIntegrationUtilities_Folder.createFolderInBox(createBox,'4yO2bWC19KUPeFdPNi36BAWRyjwfdLVj');
                 System.debug('Folder ID : '+boxFolderDetails.id);
                 System.debug('Folder Name : '+boxFolderDetails.name);
                 return null;
              }              
         }

        return null;

Best Answer

I'm not sure you will be able to solve that issue in an interactive context. You might have to use something like Batch Apex or Future methods to get around it. I have had a similar issue with Mixed DML and overcame it using Batch Apex.

So, firstly, I created a simple interface

public interface IAction 
{
    void process(BatchJob job);
}

Then, I created a couple of work classes to do the work for each type of action:

public class FolderCreator implements IAction
{
   public void process( BatchJob job )
   {
        // inject some state here and do the business
   }
}

public class CustomSettingUpdater implements IAction
   public void process( BatchJob job )
   {
        // inject some state here and do the business
   }
}

Then, in your start method of your Batch Apex, build up a list of IActions, for example

List<IAction> actions = new List<IAction>();
actions.add( new FolderCreator() );
actions.add( new CustomSettingsUpdater() );

Then, set your batch size to 1 and iterate over the actions thus isolating each action from one another, e.g..

for( IAction action : (List<IAction>)scope )
{
    action.process(job);
}

Not ideal having to use Batch Apex when really I didn't want to but it worked for me.

Related Topic