function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
dev401hasdev401has 

Can't we write Savepoint and Rollback in two different methods in a extension class?

Can i write savepoint in one method and rollback in other method?

 

I am having a visualforce page and on call of one method i am setting savepoint and then few records are inserted and updated then later on click of a button it calls another method which should rollback the changes.

 

If I declare savepoint inside a method then it gives error for variable does not exist in rollback and if it is declared outside then it gives error of System.SerializationException: Not Serializable: System.Savepoint

SteveBowerSteveBower

You have to declare it outside the Method, in the body of the controller, otherwise it won't persist past the method invocation.    But then, yes, you should be able to set a savepoint in one method (for example the Controller constructor) and roll it back in some other method (perhaps as the result of an exception, etc.)

 

Savepoints should be being treated as Transient automatically by Apex, so it seems odd to me that your're getting a serialization exception.   You're not trying to use it across a controller and a component are you?   e.g. passing it?   Or packaging it up in your own internal class which is being serialized?   Prrhaps post the code...?

 

Best, Steve

dev401hasdev401has

Hi Steve,

 

I have declared SavePoint outside only.

I am not using it in any component or anything.

 

I am having one page. on click of a checkbox and a button something is inserted on base of calculation of few fields.

and it is rendered to second portion of page. Now on that second rendered portion there are two buttons save and cancel. If cancel is clicked then that inserted thing should be rolled back.

So in the first method where insertion is done. I have used savepoint there and in the second method of cancel i have declared rollback.

 

generally it gives serialization error when savepoint is not declared as transient. but when i declare the savepoint as transient then it becomes null in another method and gives error as argument passed cannot be null in database.rollback(sp);

 

What could be the reason that it gets null? any idea?

 

 

sfdcfoxsfdcfox

Transient in Apex Code translates into "not saved in the view state." Variables not saved in the view state will be null each time a new Action is called. They are valid from the time the first setter is called until the last getter is called, and then the contents are effectively nulled out of existence.

 

A transaction (as in, a database transaction) in Salesforce is valid for one single execution unit. When you successfully return from the last method (in a traditional language, the deconstruction routines), commit is called and everything is permanently saved to the database. At that point, your only choice is to delete the already-created record.

 

Your first page should validate all the information you require (remember, your record is still in the view state until they leave the page), then on the second page, once they confirm the action, perform the desired operation.

 

Edit: Not to confuse the issue, but you can use a rollback variable between methods, so long as you're in the same execution unit. For example, this works:

 

 

public with sharing class testController {
  Database.SavePoint sp;
  public void action1() {
    sp = Database.setSavePoint();
    // do stuff here
    action2();
  }
  public void action2() {
    Database.rollback(sp);
  }

 In this case, as long as action1 is called, the rollback occurs as expected. If action2 is called first, an error occurs.

 

dev401hasdev401has

Hi @above

 

Thanks for the reply.

Didnt get u exactly about the view state. Is it not like if we are still on the same page then its a valid view state? I mean if the page call 5 different methods then they all are in same view state? I am bit confused.

 

the methods which are being called for savepoint and rollback are on same page and I thought it should be on same view state. I am posting code structure here. can you please provide some more light on it?

 

Here's the code which is being used:

 

 

<apex:pageBlock title="ABCD" rendered="{!checkpage}">
    <apex:outputPanel >
        <apex:form style="text-align:center">
             <apex:outputText style="font-weight:bold;">
             <b> Click here to create something.... </b>
             </apex:outputText> 
         <br/><br/>
              <apex:pageBlockTable value="{!list}" var="m" rendered="!checkpage}" border="0" style="text-align:left;" columns="4" >
                    <apex:column value="{!m.column1}" width="10px" >
                          <apex:facet name="header">Column 1</apex:facet>
                    </apex:column> 
                    <apex:column headerValue="Column 2" value="{!m.column2}" width="10px"/>
                    <apex:column headerValue="Create record" width="10px">
                        <apex:inputCheckbox value="{!m.column3}" rendered="{!m.selected}" id="chkbox"  >
                              <apex:actionSupport event="onclick" action="{!pgrefresh}" />
                        </apex:inputCheckbox>
                    </apex:column> 
              </apex:pageBlockTable>
                        <br/><br/>

              <apex:commandButton value="Take Action " style="font-size: 12px; height: 25px ;" action="{!createsomething}"/>
              <apex:commandButton value="Cancel" action="{!backtoMainPage}" style=" font-size: 12px;height: 25px "/>
        </apex:form>
    </apex:outputPanel>
</apex:pageBlock>

<apex:pageBlock title="Summary" rendered="{!NOT(checkpage)}">
    <apex:pageMessages />
    <br/><br/>
       <apex:form >
            <apex:repeat value="{!List2}" var="a">
                <apex:PageBlockTable value="{!a.mp}" var="mte" rendered="{!NOT(checkpage)}" width="100%">
                    <apex:column headerValue="Column1" width="25%">{!mte.col1}</apex:column>
                    <apex:column headerValue="column2" width="25%"><apex:outputField value="{!mte.col2}"/></apex:column>
                </apex:PageBlockTable>
                <br/><br/>
            </apex:repeat>
            <br/><br/>

            <apex:commandButton value="Done"  action="{!savesomething}" ></apex:commandButton>
            <apex:commandButton value="Cancel" action="{!canceltomainPage}"></apex:commandButton>
        </apex:form>
</apex:pageBlock>

 

 

Apex: Class:

 

transient Savepoint sp;
    
    public pagereference createsomething()
    {
        
        sp = Database.setSavepoint();
	system.debug('savepoint 1------------>'+sp);
	insert something;
        return null;
    } 
    
    public pagereference backtoMainPage()
    {
        PageReference back = new PageReference('/apex/vfpage?id'+Id);
        back.setRedirect(true);
        return back;
    }

public boolean checkpage
    {
        get
        {
             if(chkpg==false && chkpg2==false)
	        return true;
             else
	        return false;
        }
        private set;
        
    }

public PageReference canceltomainPage()
    {
                
        system.debug('savepoints rollback--------------->'+ sp);
        database.rollback(sp);

        PageReference cancel= new PageReference('/apex/VFPage2?id='+id);
        cancel.setRedirect(true);
        return cancel; 
        
    }

 

 

 

 

 

 

sfdcfoxsfdcfox

View state is valid even if you move to a different page, as long as the pages have the same controller and extensions. That's not the issue here. What is important is the order of operations, and what the effects of those operations are. Every time the page is called, it goes through a particular set of actions. One entire set of actions is a single transaction. Let's say your page is called "thePage". When you view the page, Salesforce goes through a series of actions, which generally look like the following:

 

1) Load the appropriate classes into memory, initialize memory heap, use an implied Database.setSavePoint().

2) If the View State is empty (i.e. you are visiting the page the first time), call the page's constructor methods.

3) If View State is not empty, load those memory variables into the object (deserialization).

4) If View State is not empty, call each of the Setter methods for all values that were rendered into the form from the last action.

5) If an "action" was called, perform the action.

6) Call the getter methods and render the page's output.

7) Set the view state for the form and output the total results (Serialization).

8) Call the implied Database.commit() if nothing went wrong in any prior step.

 

Now, I'm not claiming that these are the exact steps, or the precise order, but what's important here is step 1 and step 8. A transaction is started before each page action, and completed at the end of each action.

 

Every time you call back to the server, it is one complete transaction. For example, if you press a "Next" button, then press a "Save" button, even though you're on the same page, with the same view state throughout, you've had three distinct database transactions (the initial load, the Next action, and the Save action). You can't roll back changes between each transaction, because the transaction is already complete.

 

This is the same inherent design with every major RDBMS out there on the market-- when one whole transaction is done, the data is committed. In every major database out there, each page served results in one entire transaction. There's almost no way to place transactions on hold across pages (this usually requires persistent server sockets and some pretty low-level programming techniques that most would rather not attempt).

 

While View State can hold almost any data, the database can't place the transaction in a holding pattern indefinitely. It must immediately commit or rollback the entire transaction before the end of a single transaction unit, and the default is to commit unless there is an uncaught exception or error that causes it to rollback automatically, or the programmer manually rolls back a transaction.

dev401hasdev401has

Hi @above

 

Thanks for the reply. Very well explained. It was clear and detailed explanation!

In my case view state will change and hence that savepoint gets back to null i.e will not be set for the new view state.

 

thanks again.

SFDCJerkSFDCJerk

Thanks a lot for the reply it helped me with my work. Thanks a ton Bro : )

Suraj Tripathi 47Suraj Tripathi 47
Hi,
Greetings!

In salesforce, whenever a record is updating. The salesforce database creates a Savepoint and locks the record so no other process can use that.
In the process of the update, if any error occurs, salesforce rolls back to the previous version of the record using the Savepoint.

If you find your Solution then mark this as the best answer. 

Thank you!

Regards,
Suraj Tripathi