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
Subhodeep DeySubhodeep Dey 

Trigger bulkification issue for create multiple child records

Hi All,

 

I am facing bulkification issue on creating multiple child records from insert multiple parent record using data loader. It's showing  "10:53:29:088 FATAL_ERROR System.LimitException: Too many DML rows: 10001".

 

Please help me for fixing the issue.

 

trigger OppTrigger on Opportunity (after insert, after update, before delete) {
    
    // Record Insert Code
    if(trigger.isInsert || trigger.isundelete){
        if(checkRecursive.runOnce()){
            Set<Id> oppId = new Set<Id>();
            Map<Id,Opportunity> oppmap = new Map<Id,Opportunity>();
            for(Opportunity opp: Trigger.new){
                oppId.add(opp.Id);
            }
            List<Projected_Opportunity__c> proOppList = new List<Projected_Opportunity__c>();
            for(Opportunity opps: [SELECT ID,Name,StageName,Probability,
                                   CloseDate,Month_No__c,Implementation_Date__c,
                                   Contract_Term__c,Amount,Projected_Revenue_1__c,
                                  Q1RF_target__c,Total_Project_Revenue__c FROM Opportunity WHERE ID IN:oppId]){
                  
                 for(Integer i=0; i< Integer.valueOf(opps.Contract_Term__c); i++){
                      Projected_Opportunity__c  po = new Projected_Opportunity__c();
                        po.Opportunity__c = opps.Id; 
                        po.Opportunity_Name__c = opps.Name; 
                        po.Stage__c = opps.StageName;
                        po.Probability__c = opps.Probability;
                        po.Closed_Date__c = opps.CloseDate;
                        po.Month_No__c = opps.Month_No__c;
                        po.Projected_Implementation_Date__c = opps.Implementation_Date__c.addMonths(i);
                        po.Contract_Term__c=opps.Contract_Term__c;
                        po.Amount__c = opps.Amount;
                        po.Monthly_Projected_Revenue__c = opps.Projected_Revenue_1__c;
                        po.Target_Revenue__c = opps.Q1RF_target__c;
                        po.Total_Project_Revenue__c = opps.Total_Project_Revenue__c;
                        proOppList.add(po);
                }                      
                
            }
            if(!proOppList.isEmpty()){
                insert proOppList;
            }
            

        /*    List<Projected_Opportunity__c> polistInsertRecords = new List<Projected_Opportunity__c>();
          for(Opportunity opps: Trigger.new){
                   for(Integer i=0; i< Integer.valueOf(opps.Contract_Term__c); i++){
                      Projected_Opportunity__c  po = new Projected_Opportunity__c();
                        po.Opportunity__c = opps.Id; 
                        po.Opportunity_Name__c = opps.Name; 
                        po.Stage__c = opps.StageName;
                        po.Probability__c = opps.Probability;
                        po.Closed_Date__c = opps.CloseDate;
                        po.Month_No__c = opps.Month_No__c;
                        po.Projected_Implementation_Date__c = opps.Implementation_Date__c.addMonths(i);
                        po.Contract_Term__c=opps.Contract_Term__c;
                        po.Amount__c = opps.Amount;
                        po.Monthly_Projected_Revenue__c = opps.Projected_Revenue_1__c;
                        po.Target_Revenue__c = opps.Q1RF_target__c;
                        po.Total_Project_Revenue__c = opps.Total_Project_Revenue__c;
                        polistInsertRecords.add(po);
                } 
                
            }
            system.debug('polistInsertRecords ' + polistInsertRecords); 
            if(!polistInsertRecords.isEmpty()){
                insert polistInsertRecords;
            }*/
            /*try{
                if(polistInsertRecords.size() >0){
                       insert polistInsertRecords; 
                         system.debug('Record Inserted...');  
                    }
                 }catch(DmlException  e){
                    system.debug(e.getMessage());
                    system.debug(e.getLineNumber());
              }    */
        } 
    }
    //Code for update records
    if(trigger.isUpdate){
        if(checkRecursive.runOnce()){
            Set<Id> oppids = new Set<Id>();
            List<Projected_Opportunity__c> polistInsertRecords = new List<Projected_Opportunity__c>();
          
            for(Opportunity op : trigger.new){
            
                 oppids.add(op.id);
                
            }
            
           
            List<Projected_Opportunity__c> proOppForDel = new List<Projected_Opportunity__c>([Select Id,Opportunity_Name__c,Amount__c,
                                                                                                       Closed_Date__c,Stage__c,Probability__c,
                                                                                                     Projected_Implementation_Date__c,Contract_Term__c,
                                                                                                     Monthly_Projected_Revenue__c,Target_Revenue__c 
                                                                                              From Projected_Opportunity__c 
                                                                                              Where Opportunity__c IN:oppids]);
                                                    
            Delete proOppForDel;
            
            for(Opportunity opps : Trigger.new){ 
                for(Integer i=0; i< opps.Contract_Term__c; i++){
                      Projected_Opportunity__c  po = new Projected_Opportunity__c();
                        po.Opportunity__c = opps.Id; 
                        po.Opportunity_Name__c = opps.Name; 
                        po.Stage__c = opps.StageName;
                        po.Probability__c = opps.Probability;
                        po.Closed_Date__c = opps.CloseDate;
                        po.Month_No__c = opps.Month_No__c;
                        po.Projected_Implementation_Date__c = opps.Implementation_Date__c.addMonths(i);
                        po.Contract_Term__c=opps.Contract_Term__c;
                        po.Amount__c = opps.Amount;
                        po.Monthly_Projected_Revenue__c = opps.Projected_Revenue_1__c;
                        po.Target_Revenue__c = opps.Q1RF_target__c;
                        po.Total_Project_Revenue__c = opps.Total_Project_Revenue__c;
                        polistInsertRecords.add(po);
              
                  } 
                }system.debug('polistInsertRecords ' + polistInsertRecords); 
             try{
                if(polistInsertRecords.size() >0){
                       insert polistInsertRecords; 
                         system.debug('Record Inserted...');  
                    }
                }catch(DmlException  e){
                    system.debug(e.getMessage());
                    system.debug(e.getLineNumber());
             }    
        } 
     }
}

ashishashish
An absolute limit of 100 records that can be updated via a DML statement per trigger execution, here the error is in for Loops Condition "  for(Integer i=0; i< Integer.valueOf(opps.Contract_Term__c); i++)" ,try to look for some other solution rathr then using this
Glyn Anderson 3Glyn Anderson 3
You can do this by moving all your DML into @future methods.  This should be acceptable, especially for bulk uploads using DataLoader.  Your Users will have to be trained to wait a few seconds before expecting to see the new Projected Opportunity records.  You can call up to 50 @future methods in a single transaction; and @future methods have more CPU time available.  The code below breaks the DML of new Projected Opportunities into batches of about 2000 records.  (You can adjust this number.)  With 50 @future calls, you should be able to insert around 100,000 records (and delete the old ones).  Let me know if you have any questions.  Disclaimer:  This code is untested and may contain typos.

<pre>
trigger OppTrigger on Opportunity ( after insert, after update, after undelete )
{
    if ( ! CheckRecursive.runOnce() ) return;

    Set<Id> oppIds = new Set<Id>();
    Integer numProOpps = 0;
    for ( Opportunity opps : Trigger.new )
    {
        oppIds.add( opps.Id );
        numProOpps += Integer.valueOf( opps.Contract_Term__c );

        if ( numProOpps >= 2000 )   // adjust this number to your liking
        {
            OppTriggerUtils.replaceProjectedOpportunities( oppIds );
            oppIds.clear();
            numProOpps = 0;
        }
    }

    if ( !oppIds.isEmpty() )
    {
        OppTriggerUtils.replaceProjectedOpportunities( oppIds );
    }
}

public class OppTriggerUtils
{
    @future
    public static void replaceProjectedOpportunities( Set<Id> oppIds )
    {
        // this will not error if there are no records to delete
        delete [SELECT Id FROM Projected_Opportunity__c WHERE Opportunity__c IN :oppIds];

        List<Projected_Opportunity__c> proOppList = new List<Projected_Opportunity__c>();
        for ( Opportunity opps :
            [   SELECT  Id, Name, StageName, Probability, CloseDate, Month_No__c,
                        Implementation_Date__c, Contract_Term__c, Amount,
                        Projected_Revenue_1__c, Q1RF_target__c, Total_Project_Revenue__c
                FROM    Opportunity
                WHERE   Id IN :oppIds
            ]
            )
        {
            for ( Integer i = 0; i < Integer.valueOf( opps.Contract_Term__c ); i++ )
            {
                proOppList.add
                (   new Projected_Opportunity__c
                    (   Opportunity__c = opps.Id
                    ,   Opportunity_Name__c = opps.Name
                    ,   Stage__c = opps.StageName
                    ,   Probability__c = opps.Probability
                    ,   Closed_Date__c = opps.CloseDate
                    ,   Month_No__c = opps.Month_No__c
                    ,   Projected_Implementation_Date__c = opps.Implementation_Date__c.addMonths(i)
                    ,   Contract_Term__c = opps.Contract_Term__c
                    ,   Amount__c = opps.Amount
                    ,   Monthly_Projected_Revenue__c = opps.Projected_Revenue_1__c
                    ,   Target_Revenue__c = opps.Q1RF_target__c
                    ,   Total_Project_Revenue__c = opps.Total_Project_Revenue__c
                    )
                );
            }                      
        }
        insert proOppList;
    }
}
</pre>
 
Subhodeep DeySubhodeep Dey

Hello Glyn,

 

Greetings of the day!

Thanks for your response.

 

I have implemented your logic.But it's working sometimes and sometimes not. And also in the child records, Monthly Projected Revenue __c, and Account__c values are not fetching.

 

Glyn Anderson 3Glyn Anderson 3
When it fails to work, what happens wrong?  Do all records fail to be created?  Or only some?  Or are the records created with the wrong values?  Or some other failure?

What do you mean by "values are not fetching"?  Are they being set to null?

Let me know and I'll try to help you figure out what's going on.
Subhodeep DeySubhodeep Dey

Hello Glyn,

The very first time the records in child object "Projected Opportunity" from opportunity having 2 value in contract term is created, but it's not updating. And also when I am creating new opportunity it's not creating any child records.

Glyn Anderson 3Glyn Anderson 3
Do you have more than one trigger on Opportunity?  If so, it might be a problem with the "CheckRecursive.runOnce()" call.  If the other trigger runs first and sets the recursion prevention flag, then subsequent triggers (like this one) won't run.  Try commenting out that line in the trigger and see what happens.

If you're sure you DON'T have more than one trigger on Opportunity, let me know that, too.
Subhodeep Dey 1Subhodeep Dey 1
There is no other trigger or classes written for the opportunity except the above, where this recursive class is used.
Glyn Anderson 3Glyn Anderson 3
OK.  Are there any workflow rules that do field updates?  Have you tried commenting out the CheckRecursive.runOnce() call?  Have you looked at debug logs?  You could add some System.debug() statements and see what's happening.  It's hard for me to debug this in my head, especially when it looks like it should work.  I need your help to try some things and let me know what happens.
Subhodeep DeySubhodeep Dey

Hey Glyn,


Greetings of the day!

Sure, I am alway ready to help you. 
I have added multiple debug logs in the trigger and the helper class. I found that the actual error is in line no 23 of oppTrigger.
The error is "FATAL_ERROR System.AsyncException: Future method cannot be called from a future or batch method: OppTriggerUtils.replaceProjectedOpportunities(Set<Id>)".
I have tried commenting out the CheckRecursive.runOnce(), but then also the same error occurred.

I have also attached a screenshot for the same.

User-added image

Glyn Anderson 3Glyn Anderson 3
It sounds like you have a batch job or another @future method that inserts or updates Opportunities.  In that case, you won't be able to use an @future method in your Opportunity trigger.  Are there any triggers on Projected_Opportunity__c?  If so, do they update Opportunities?  This could cause an indirect recursion problem (A updates B, B updates A).

I'm sorry I can't just tell you what the problem is.  You're going to have to do some debugging.  Start by trying to determine why it thinks our @future is being called from another @future or batch.
Glyn Anderson 3Glyn Anderson 3
Any luck with this?  Have you figured out the problem?
Subhodeep Dey 1Subhodeep Dey 1

Hello Glyn,

Thanks a lot for all your support!
I have learned so many new logic from the code shared by you.

Actually, there is no other trigger or classes written for that child object and opportunity. And also none of the automation rules were created for the same.

Actually, the issue in bulk data loading. As the governor limit of data loading in Salesforce is 10000, that's why the error has occurred. 

Means, I have tried to import  110 opportunities with 99 child object for each opportunity
 
So the total records is 110 Projected_Opportunities  * 99 + 110 Opportunity = 11000. Which cross the SFDC governor limit.

When I tried to import 88 Projected_Opportunities  with 110 Opportunities. It's successfully imported.
110 Projected_Opportunities  * 88 + 110 Opportunity = 9790.  Which comes under the SFDC governor limit.

 

I request you to plz help me in future also, whenever I need. I'll be always thankful to you for this.

 

 

Subhodeep Dey 1Subhodeep Dey 1


Hello Glyn,

 

I have a new issue in one of the project.

I have a task assigned to customized the volunteer package and add more filters on it. I have implemented the same. but actually, there is some error in the print view page.  

 

I need to fetch all parent object record based on a filter in the child object. 

SOQL:- Select name, (select id,name from GW_Volunteers__Volunteer_Shift__r) from GW_Volunteers__Volunteer_Job__c

Parent: - GW_Volunteers__Volunteer_Job__c
Child:- GW_Volunteers__Volunteer_Shift__r

Error:-

 

"Didn't understand relationship 'GW_Volunteers__Volunteer_Shift__r' in FROM part of query call. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names."

 

Please help me!

Glyn Anderson 3Glyn Anderson 3
Hi Subhodeep,

The thing with child relationships is that they're not always named what you think they should be.  First, I would try using "GW_Volunteers__Volunteer_Shifts__r" (notice that the plural, "Shifts").  The default child relationship name is always the plural of the child object name.  If that doesn't work (or you can do this first), in Setup, go to the GW_Volunteers__Volunteer_Shift__c object definition and click on the field that looks up to GW_Volunteers__Volunteer_Job__c.  In the Field Information section, in the right-hand column, is the Child Relationship Name.  Use that value (with "__r" appended).
Subhodeep Dey 1Subhodeep Dey 1

Hey Glyn,

The issue is fixed now. Thanks for your support.

 

Now I am stuck on a new logic.

I need to set a default picklist value in VF page when it's loading.

What should I do, I don't have any idea.

I have updated the constructor to display the default value but it's not working.

Controller Code: -

 global string Shift_Cancellation_Status { get; set; }
     // the list of Shift Cancellation Status List

    global list<SelectOption> Shiftss_Cancellation_Status_List {
        get {
              
            list<SelectOption> listSO =new  list<SelectOption>();   
            //listSO.add(new selectoption('','(all shift cancellation status)'));
            listSO.add(new selectoption('all shift cancellation statuses','(all shift cancellation statuses)'));    
            listSO.add(new selectoption('Canceled by Organization = FALSE','Canceled by Organization = FALSE'));
            listSO.add(new selectoption('Canceled by Organization = TRUE','Canceled by Organization = TRUE'));
             return listSO;
        } 
        
        set;
    } 
    
VFPAGE code: -

 <div class="slds-form-element">
                            <apex:outputLabel value="Shift Cancellation Status" for="ddlShiftCancellationStatus" styleClass="slds-form-element__label" />
                                <div class="slds-form-element__control">
                                        <div class="slds-select_container">
                                            <apex:selectList id="ddlShiftCancellationStatus" value="{!Shift_Cancellation_Status}" size="1" styleClass="slds-select" >
                                                          <apex:actionSupport immediate="false" event="onchange" rerender="panelPrint"
                                                           status="retrieveStatus" action="{!ChangeShiftCancellationStatus}" />
                                                          <apex:selectOptions value="{!Shift_Cancellation_Status_List}" />
                                           </apex:selectList>
                                        </div>
                                </div>
                        </div>

 

Plz help me!