I am getting an error when trying to kick off an approval flow programatically. I have seen others run into a similar issue with the DML not allowed.

Why is DML not allowed in Constructor?

I tried to follow a quick easy solution however my debug statement does not fire on my action but it does in the constructor. Is there a way around this. I am really just trying to kick off an approval flow by clicking a button.


Public class G_SubmitAllPartsUsedApproval {

    Private Case soMyCase;
    Public  List<Part_Used__c> lstPartsUsed {get; set;} 
    Private boolean doDML;

    Public G_SubmitAllPartsUsedApproval(ApexPages.StandardController stdController) 
        doDML= true;
         system.debug(logginglevel.debug, 'DEBUG: Start G_SubmitAllPartsUsedApproval Constructor' );
         // Get Case ID number 
        This.soMyCase = (Case)stdController.getRecord(); 

        //Get the Case Values for this record
        soMyCase = [Select Id, AccountId, AssetId, CaseNumber, ContactId, PriceBook_Currency_Code__c
                   From Case 
                        Where Id = :This.soMyCase.Id];

        lstPartsUsed = [Select Id
                     From Part_Used__c 
                        Where Case__c = :soMyCase.id];

        system.debug(logginglevel.debug, 'DEBUG: lstPartsUsed is:    '  + lstPartsUsed );

        For (Part_Used__c soPartsUsed : lstPartsUsed){




    Public Void SubmitForApproval(Part_Used__c PartsUsed)

        system.debug(logginglevel.debug, 'DEBUG: PartsUsed is:    '  + PartsUsed );

        Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
        req1.setComments('Submitting request for approval automatically using Trigger');
        Approval.ProcessResult result = Approval.process(req1);


    public pagereference doSomeDMLStuff(){
        system.debug(logginglevel.debug, 'DEBUG: doDML is:    '  + doDML );
         //run DML statements 
    system.debug(logginglevel.debug, 'DEBUG: doDML is:    '  + doDML );
     return null;



<apex:page standardController="Case" extensions="G_SubmitAllPartsUsedApproval" action="{!doSomeDMLStuff}">

Button Javascript

window.location = 'apex/G_SubmitAllPartsUsedApproval?id={!Case.Id}';
  • I'm noticing that your questions still aren't correctly formatting multi-line code. A multi-line code block is formatted by ensuring that every line has at least 4 blank spaces at the start of the line. The easy way to do this (while preserving all of your indentation) is to paste your code, highlight it, and then press ctrl +k (cmd + k on Mac)
    – Derek F
    Commented Jul 25, 2018 at 13:43

1 Answer 1


when you submit a record for approval. It treats as a DML(because of lock and unlock feature) so that you are doing in your constructor.

You can move your approval functionality to doSomeDMLStuff method and since doSomeDMLStuff called from apex:page action attribute. You will not face any issue using this way.

Documentation: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_approval.htm

Salesforce admins can edit locked records. Depending on your approval process configuration settings, an assigned approver can also edit locked records. Locks and unlocks that are set programmatically use the same record editability settings as other approval-process locks and unlocks.

Record locks and unlocks are treated as DML. They’re blocked before a callout, they count toward your DML limits, and if a failure occurs, they’re rolled back along with the rest of your transaction. To change this rollback behavior, use an allOrNone parameter.

Approval is also used as a namespace for the ProcessRequest and ProcessResult classes.

You must log in to answer this question.

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