3

In my custom edit page for LineItem__c records I have overriden the save button with my own implementation which does not only save the record itself but also change to child records.

<apex:page standardController="LineItem__c" extensions="LineItemEditCtrlExt">

    <head><title>{!DeliverableLineItem__c.Name}</title></head>

....

      <apex:pageBlockButtons >
          <apex:commandButton value="Save" action="{!doSave}" />
      </apex:pageBlockButtons> 

      <apex:pageBlockSection>
          <apex:repeat value="{!$ObjectType.DeliverableLineItem__c.fieldsets.EditBasic}" var="field">
              <apex:inputField value="{!lineItem[field]}"  />
          </apex:repeat>
      </apex:pageBlockSection>

To handle errors in an ACID-way I rollback to a Savepoint in case an exception is thrown.

public with sharing class LineItemEditCtrlExt  {

    public LineItem__c lineItem { get; set; }
    public ApexPages.StandardController stdCtrl;


    public LineItemEditCtrlExt(ApexPages.StandardController stdCtrl) {
        this.stdCtrl = stdCtrl;
        lineItem = (LineItem__c) stdCtrl.getRecord();
    }


    public PageReference doSave() {
        Savepoint toBeforeState = Database.setSavepoint();

        try {
            upsert lineItem;
            saveChildrenX();
            saveChildrenY();

            return stdCtrl.view();
        }
        catch(Exception ex) {
            ApexPages.addMessages(ex);

            // No error when I comment out next line!!
            Database.rollback(toBeforeState);

            return null;
        }
    }
    ...
}

But this always leads to strange

Data not available

errors when the user tries to save again after he was presented with a error message meaning a user clicks Save, sees an validation error on the page and then immediately clicks Save again.

This does not happen at all when I remove the Database.rollback() call. Why is that so? And how should I rewrite my custom save to work?

2

If the database upsert results in an ID value being allocated and set on the SObject, that ID value remains in the Apex code even though the ID value has been discarded as part of the rollback process in the database. So the next time you upsert the data for that ID is "not available".

So add this (a clone that does not preserve the ID) right after the rollback:

lineItem = lineItem.clone(false, false, false, false);

PS

Or as discussed in the comment thread, removing the savepoint/rollback might be the best solution. See the Transaction Control documentation; savepoint/rollback is provided for special cases.

| improve this answer | |
  • you mean lineItem = lineItem.clone(false, false, false, false)?! – Robert Sösemann Nov 24 '14 at 11:11
  • @RobertSösemann Yep. I'll change that. – Keith C Nov 24 '14 at 11:13
  • I added that line and it didn't change anything :-( – Robert Sösemann Nov 24 '14 at 11:13
  • @RobertSösemann OK, then have a look for that kind of problem in saveChildrenX and saveChildrenY. – Keith C Nov 24 '14 at 11:14
  • 1
    @RobertSösemann My first suggestion would be to lose the savepoint/rollback as the transaction won't commit if there are DML errors. But perhaps you need it for some other reason... – Keith C Nov 24 '14 at 11:34

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.