0

I have a component which makes a webservice callout and this runs successfully in a standalone context - ie within a test page. However the component needs to go within a page that uses the standard set controller and this seem to give the uncommitted work pending error even thought there is no DML.

So am I right to conclude that invoking the standard set controller leaves uncommitted work pending, and if so, is there a way to close the SSC down before making the callout? save() doesn't seem to do it.

The alternative is to make the callout @future but this will involve additional complication since the response is required in the page.

1 Answer 1

0

You can't make callouts, HTTP or otherwise, once you have made changes to the database. It's true that you cannot make callouts with pending transactions in the request context. Also, it's not possible to do an explicit commit. So your only way out is to make the callout in a separate context.

You cannot perform a DML operation prior to a callout. All the DML operations should be invoked only after you are done with callouts.So, make a webservice callout first and then save the request.

If you are making multiple callouts, then save all the requests in a list or map and post callouts you save them.

Basically the following scenario will work :-

query callout query callout insert

callout callout callout insert or update

But the following scenario will fail :-

callout insert callout <---- fails here

Possible workaround :-

1) You either need to commit the transaction, make the callout prior to any database changes or move your callout to an @future method (place @future annotation to the webservice method).

2) Splits the transaction into two separate Ajax processes. The first inserts the record and the second performs the callout and is able to update the newly inserted record.

You can save the records and then respond to the user with a temporary page with a "Loading" message as you make the second call back to perform the callout. To make it look seamless, you can also make successive AJAX calls to save records and to make callout as user sees "Loading" message upon clicking "Save" button.

4) Sometimes customer do not want to place @future annotation to the webservice method as they need a response from the webservice to decide if they have to rollback the insert or not ?

They can execute an action to insert the object and then execute the webservice callout on the oncomplete event of a commandButton. Then, return a PageReference giving the user immediate feedback. If the webservice callout returns any error, then delete the object and returning the user back to the same page.

See bellow:

@VisualforcePage

 <apex:actionFunction name="executeWS" action="{!executeWS}"></apex:actionFunction>
 <apex:commandButton value="Save" action="{!save}" oncomplete="executeWS()" />

@Controller

public PageReference save() {
 insert obj;
}

public PageReference executeWS(){
 obj = [SELECT ...];
 try{
  callout ws;
 } catch(System.Exception ex){
  delete obj;
  ApexPages.addMessages(e);
  return null;
 }
 return new PageReference('/' + id);
}
1
  • Thanks but I know all that. I am specifically asking in respect of the standard set controller since I am NOT doing any DML prior to the callout but I DO have a standard set controller invoked in the base page. So my scenario is: SSC query callout. It would be good if I could save or otherwise commit 'open' transactions that result from using the SSC in a context prior to making the callout (which you can do with normal DML using apex:actionFunction) but I can't figure out how to do this. Commented Jul 15, 2015 at 12:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .