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
sparktestsparktest 

@ future causing error in class - creating detail records from master record insert - more than 100

I have an after update trigger that fires the below class.  I am creating a number of related records depending on values in the master object.  I have seen some of the examples of @future and I am not sure if I can even do this. 
 
Is there a better way? I am bumping up against the limit and I was hoping @future would take care of it, but I get an error of
 
"Save error: Unsupported parameter type LIST:SOBJECT:Site_Lease_Contract__c SiteLeaseCumCostUpdate/src/classes SiteLeaseFncTblClass.cls line 4"
 
When I try to save as below (minus the '@future' is works fine)
 
 
Code:
public class SiteLeaseFncTblClass 
{
 @future
 public static void SiteLeaseFncTblTrigger(Site_Lease_Contract__c[] newSiteLeaseFncTbl) 
 {
  for (Integer i = 0; i < Trigger.new.size(); i++) {
   
      List<SiteFnc__c> followuprecords = new List<SiteFnc__c>();
      
       Boolean GT = newSiteLeaseFncTbl[i].Generate_Table__c;
       Boolean AR = newSiteLeaseFncTbl[i].Auto_Renewed__c;
       Double Months = newSiteLeaseFncTbl[i].Lease_Term_In_Months__c;
       Double RMonths = newSiteLeaseFncTbl[i].Renew_Term__c;
       Double RTerms = newSiteLeaseFncTbl[i].Renew_Addl_Terms__c;
       String LeaseID = newSiteLeaseFncTbl[i].id;
       Date MonthBegin = newSiteLeaseFncTbl[i].Start_Date__c;
       Double escamt = (newSiteLeaseFncTbl[i].Escalation_Amount__c/100)+1;
       Double escmth = newSiteLeaseFncTbl[i].Escalation_Month__c;
       Double RentToPay = newSiteLeaseFncTbl[i].Initial_Rent__c;
       Double SLD = newSiteLeaseFncTbl[i].Straight_Line_Depr__c;
       
    if (GT == True)
    {
     Double j = Months;
     
     If (AR == True)
     {
         j = Months + (RMonths * RTerms);
     }
        Integer Count = 1;
        Integer CycleInsert = 1;
      
        for (Integer k = 0; k < j; k++) {
          
         if (escmth == k+1)
         {
          RentToPay = RentToPay * escamt;
         }
         if (k+1 > escmth)
         {
          Count = Count + 1;
         }
         if (Count == 12)
         {
          Count = 1;
          RentToPay = RentToPay * escamt;
         }
       
         SiteFnc__c SiteFnc = new SiteFnc__c(
         Site_Lease__c = LeaseID,
      Date__c = MonthBegin.addmonths(k),
      Cumulative_Def_Rent_Obl__c = SLD * (k+1),
      Rent__c = RentToPay);
     
         followuprecords.add(SiteFnc);
        }
        insert followuprecords;
    }
     }
 }  
}

 
aalbertaalbert
Try moving the "insert" DML statement outside the FOR loop. Since you are executing a insert statement for each iteration of the FOR loop, you will hit the governor limit of 100 quite easily. Instead, in the FOR loop, build the list or collection of objects to insert, then make the insert statement with a batch of records. Not 1 at a time.


JimRaeJimRae
Also, the documentation states (page 92) that mehods defined as "@future" can connot take SOjects or objects as arguments.
sparktestsparktest

thanks Albert and JR,

DOH,

I was trying to figure out the complicated answer and missed the one right in front of me.  I moved the insert 'up' one level and it works great now.

Just for the sake of argument though, I would like to have a better understanding on how to do the asynchronous insert.  I found examles on how to do it within one object, but when it comes to doing a related/master-detail insert of multiple records for the detail  I haven't found one yet. Any advice, just basic is fine so I am not digging around in the wrong place, would be great on that.

I saw the exclusion of SObjects on the @future and figured that was an issue, but I didn't know how else to pull in the Master object so I could use it to insert the related detail records.  I am new to the syntax/usage of java/apex so I apologize for the elementary questions.

Thanks,

sparktestsparktest
 
I spoke to soon.... I had to remove a 'safety' before the test, and now that I did, it does not appear to be possible to create that many records using one trigger.....whereever I put the insert relative to the loop.
 
So I am back to the @future option......
 
I am not sure how to use this one yet, but am digging around for whatever I can find on the matter.  So far, I cannot find a good example on doing what I am trying to do (the multiple detail inserts immediately following the update of a master record)....so if anyone has a good place they can point please do...
 
thanks,
JimRaeJimRae
You should be able to hold up to 1000 in your update list, and process them all in your DML statement (insert), in batches of 200.
What error are you getting?  Maybe you are still having a bulk related issue with your for loop.


sparktestsparktest
 
here is the error in the UI
 
Error:Apex trigger SiteLeaseFncTblTrigger caused an unexpected exception, contact your administrator: SiteLeaseFncTblTrigger: execution of AfterUpdate caused by: System.Exception: Too many DML rows: 120: Class.SiteLeaseFncTblClass.SiteLeaseFncTblTrigger: line 58, column 17
 
My impression was that since I was creating 120 new records (instead of the max of 100) via one trigger using a synchronous method I would get this error.  That seems like a pretty low ceiling. 
 
I did a lot of automation with the data loader and that, like you say, has a limit of 200. 
 
Thoughts?
 
Thanks,
aalbertaalbert
I wonder if you are hitting the governor that limits the "Total number of records processed as a result of DML statements". This governor scales with trigger batch size. The limit is multiplied by the number of records submitted. For example, if your trigger initiates this apex code to fire with only a single record, then you can only modify 100 records in a DML statement (ie insert).
sparktestsparktest
 
Yes, the trigger is firing based on one 'after update' of a record in the master object...'Lease' and initiating the creation of a number of records on the child (Finance) object, all records use values from the master object to calculate values on each row of the detail.   Its pretty slick, and it was fun to build, so it is unnerving that such a small limit is holding it back.
 
Do I need to use a different process to do the insert?  Here is the code.......not much different from the first post, I just moved the insert command up a couple levels, to ensure that it is doing the entire 120 record insert at once.  Is this even possible to do synchronously?
 
Thanks,
 
Code:
public class SiteLeaseFncTblClass 
{
 public static void SiteLeaseFncTblTrigger(Site_Lease_Contract__c[] newSiteLeaseFncTbl) 
 {
     List<SiteFnc__c> followuprecords = new List<SiteFnc__c>();
  for (Integer i = 0; i < Trigger.new.size(); i++) 
  {
       Boolean GT = newSiteLeaseFncTbl[i].Generate_Table__c;
       Boolean AR = newSiteLeaseFncTbl[i].Auto_Renewed__c;
       Double Months = newSiteLeaseFncTbl[i].Lease_Term_In_Months__c;
       Double RMonths = newSiteLeaseFncTbl[i].Renew_Term__c;
       Double RTerms = newSiteLeaseFncTbl[i].Renew_Addl_Terms__c;
       String LeaseID = newSiteLeaseFncTbl[i].id;
       Date MonthBegin = newSiteLeaseFncTbl[i].Start_Date__c;
       Double escamt = (newSiteLeaseFncTbl[i].Escalation_Amount__c/100)+1;
       Double escmth = newSiteLeaseFncTbl[i].Escalation_Month__c;
       Double RentToPay = newSiteLeaseFncTbl[i].Initial_Rent__c;
       Double SLD = newSiteLeaseFncTbl[i].Straight_Line_Depr__c;
       
    if (GT == True)
    {
     Double j = Months;
     
     If (AR == True)
     {
         j = Months + (RMonths * RTerms);
     }
        Integer Count = 1;
        Integer CycleInsert = 1;
      
        for (Integer k = 0; k < j; k++) {
          
         if (escmth == k+1)
         {
          RentToPay = RentToPay * escamt;
         }
         if (k+1 > escmth)
         {
          Count = Count + 1;
         }
         if (Count == 12)
         {
          Count = 1;
          RentToPay = RentToPay * escamt;
         }
       
         SiteFnc__c SiteFnc = new SiteFnc__c(
         Site_Lease__c = LeaseID,
      Date__c = MonthBegin.addmonths(k),
      Cumulative_Def_Rent_Obl__c = SLD * (k+1),
      Rent__c = RentToPay);
     
         followuprecords.add(SiteFnc);
        }
        //insert followuprecords;
    }
     }
       insert followuprecords;
 }  
}

 
JimRaeJimRae
I wonder if your DML statement is still inside your loop.  Maybe you didn't move it far enough out.  I could be that your list is collecting only one record to update, and then clearing and starting again.  Looking closer, that is what you are doing.
You need to move your list creation outside of the loop, and move the insert outside of the loop.

Code:
public class SiteLeaseFncTblClass{
 public static void SiteLeaseFncTblTrigger(Site_Lease_Contract__c[] newSiteLeaseFncTbl){
  List<SiteFnc__c> followuprecords = new List<SiteFnc__c>();
  for (Integer i = 0; i < Trigger.new.size(); i++) {
            Boolean GT = newSiteLeaseFncTbl[i].Generate_Table__c;
         Boolean AR = newSiteLeaseFncTbl[i].Auto_Renewed__c;
         Double Months = newSiteLeaseFncTbl[i].Lease_Term_In_Months__c;
         Double RMonths = newSiteLeaseFncTbl[i].Renew_Term__c;
      Double RTerms = newSiteLeaseFncTbl[i].Renew_Addl_Terms__c;
      String LeaseID = newSiteLeaseFncTbl[i].id;
      Date MonthBegin = newSiteLeaseFncTbl[i].Start_Date__c;
      Double escamt = (newSiteLeaseFncTbl[i].Escalation_Amount__c/100)+1;
      Double escmth = newSiteLeaseFncTbl[i].Escalation_Month__c;
      Double RentToPay = newSiteLeaseFncTbl[i].Initial_Rent__c;
      Double SLD = newSiteLeaseFncTbl[i].Straight_Line_Depr__c;
         
      if (GT == True){
       Double j = Months;
       if (AR == True){
            j = Months + (RMonths * RTerms);
       }
          Integer Count = 1;
          Integer CycleInsert = 1;
      
          for (Integer k = 0; k < j; k++) {
          
            if (escmth == k+1){
              RentToPay = RentToPay * escamt;
            }
            if (k+1 > escmth){
              Count = Count + 1;
            }
            if (Count == 12){
              Count = 1;
              RentToPay = RentToPay * escamt;
            }
       
            SiteFnc__c SiteFnc = new SiteFnc__c(
             Site_Lease__c = LeaseID,
           Date__c = MonthBegin.addmonths(k),
           Cumulative_Def_Rent_Obl__c = SLD * (k+1),
           Rent__c = RentToPay);
     
           followuprecords.add(SiteFnc);
          }          
      }
  }
  insert followuprecords;
 }
}

 

sparktestsparktest
I have them both outside of the for loop.  If I move them out anymore (which would put them just outside of the method/just inside the class) I get save errors/unexpected token 'list' and such.
 
As long as I keep the records at 100 or below, it works fine. 
 
Thanks,