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
SfDevForceSfDevForce 

System.Exception: Too many DML rows

I have an account with 8000+ contacts.  When the account is updated, a trigger fired and call a class method to update these 8000+ contacts.  I'm running into the 'Too many DML rows' problem.  Is it possible to do something like this with apex trigger?  Thank you.
TehNrdTehNrd
According to the Apex Reference guide http://www.salesforce.com/us/developer/docs/apexcode/salesforce_apex_language_reference.pdf
the max amount of records that can be updated from a trigger is 100.

Page 152.


Message Edited by TehNrd on 10-10-2007 05:09 PM

WrogWrogWrogWrog

How come I get an error message :

execution of AfterUpdate caused by: System.Exception: Too many DML statements: 21 

Does the "21" mean the number of DML statements? I get this when trying to set ServiceDate of a number of opportunity Line items to match the CloseDate of the parent opportunity. What is really confusing me is that there are only 18 line items on the opportunity which fails, but no eror occurs on another opportunity with 20 line items.

I've had a similar problem with errors saying "too many SOQL statements: 21" using other methods for updating.

Any ideas anyone?

Roger

Here's the full code:

Code:

trigger Opportunity_CloseDate_Update on Opportunity (after update) {

// Copy the close date of the opportunity to the line items 

 Opportunity[] opps = Trigger.new;
 // Store value of opp close date field
 Date closedate = opps[0].CloseDate;

 // Get related line items   
 ID oppId = opps[0].Id; 
 OpportunityLineItem[] items = [select Id, ServiceDate from OpportunityLineItem where OpportunityId = :oppId]; 
 
 // Set line item dates to match opportunity date
 for (OpportunityLineItem item : items){
  item.ServiceDate = closedate; 
  update item;
 }
}


 

Message Edited by WrogWrog on 11-28-2007 11:46 PM

SfDevForceSfDevForce
You might want to do batch update instead and move the 'update item' outside of the loop.
TehNrdTehNrd
Yes, in that case the 21 means the number of DML statements. The reason for this error is you are updating each line item in the loop. What you can do is apply your logic to the line items and then update all of them at once. All you need to do is take the update statement out of the loop and update the entire list rather than each line item.

Try this:
Code:
trigger Opportunity_CloseDate_Update on Opportunity (after update) {

// Copy the close date of the opportunity to the line items 

 Opportunity[] opps = Trigger.new;
 // Store value of opp close date field
 Date closedate = opps[0].CloseDate;

 // Get related line items   
 ID oppId = opps[0].Id; 
 OpportunityLineItem[] items = [select Id, ServiceDate from OpportunityLineItem where OpportunityId = :oppId]; 
 
 // Set line item dates to match opportunity date
 for (OpportunityLineItem item : items){
  item.ServiceDate = closedate; 
  }
  
  update items;

}

 

AMartinAMartin

Hi Roger,

Just wondering if you have looked into moving out product and revenue schedule dates when the close date changes? (ex. If the user moves the close date out 30 days, all the corresponding product and schedule dates get moved out by 30 days). 

My company relies heavily on revenue schedules and the existing disconnnect between close dates and schedule dates is a major issue.  Unfortuneately, I'm having a lot of trouble figuring out how to do this with Apex.

Thanks in advance for any help or advice you can offer.

Aiden

VolkerSF24VolkerSF24
I have the same problem, but I have an included loop which causes this problem:

Code:
public class billingclass 
{


 public static void addRechnung(Rechnungslauf__c[] rl)
 {
  for (Rechnungslauf__c rlf:rl)
   {
    ProductLineItem_recurring__c[] plis;
    Contract[] con;
    
   // Select aller aktiven Verträge
   
     con = [select  
          id,
          AccountID,
          Rechnungsempfaenger__c     
      from contract 
      where 
      StartDate <= LAST_MONTH and      
      EndDate >= LAST_MONTH and
      statuscode != 'Draft'
      ];
      
   // For Loop zur Erstellung der Rechungen, Bezug auf die aktiven Verträge
      
   for (contract connew:con)
    {
      
   // Definition neuer Variable zur Rechnungserstellung
     
      Rechnung__c r = new Rechnung__c();
      
   // Insert Rechnung - Relation to contractdata by variable 
           
      r.Firma__c = connew.AccountID;
      r.Rechnungsemail__c = connew.Rechnungsempfaenger__c;
      r.Rechnungslauf_ID__c = rlf.id;
      r.Vertrag_ID__c = connew.id;
      insert r;
     
   // Select der ProductLineItems mit Relation zum Vertrag aus r (Rechnung)
     
     plis = [select Verkaufspreis__c,
        Menge__c,Discount__c,
        Listenpreis__c,
        Beschreibung__c,
          Vertrag__c     
      from ProductLineItem_recurring__c
      where  Vertrag__c = :r.Vertrag_ID__c and 
        Start_Datum__c <= LAST_MONTH and
        Verkaufspreis__c >0];
   
   // For Loop zur Erstellung der Rechnungspositionen  
    
    for (ProductLineItem_recurring__c pli:plis)
     {     
      Rechnungspositionen__c rp = new Rechnungspositionen__c();   
      rp.Rechnungsnummer__c = r.id;
      rp.Leistung__c = pli.Beschreibung__c;
      rp.Einzelpreis__c = pli.Verkaufspreis__c;
      rp.Discount__c = pli.Discount__c;
      rp.Listenpreis__c = pli.Listenpreis__c;      
      rp.Anzahl__c = pli.Menge__c;
      insert rp;
      
     }
     
     //createpdfclass.deliverAsPDF(r.id);
     //createpdfclass cpc = new createpdfclass();
     //cpc.DeliverAsPDF(r.id);

      
    }
    
             
   }
   
   
 } 
}

 My Problem is this for-loop:

Code:
    for (ProductLineItem_recurring__c pli:plis)
     {     
      Rechnungspositionen__c rp = new Rechnungspositionen__c();   
      rp.Rechnungsnummer__c = r.id;
      rp.Leistung__c = pli.Beschreibung__c;
      rp.Einzelpreis__c = pli.Verkaufspreis__c;
      rp.Discount__c = pli.Discount__c;
      rp.Listenpreis__c = pli.Listenpreis__c;      
      rp.Anzahl__c = pli.Menge__c;
      insert rp;
      
     }

I'm getting about 10 line per loop, so I getting also this Errormessage:

Too many DML statements: 21: Class.billingclass.addRechnung: line 42, column 25

Do someone have any sollutions?
 


Volker_factory42Volker_factory42
I could now handle my first problem with Maps and Lists:

Code:
public class Rechnungslauf_class
{

 public static void addRechnung(Rechnungslauf__c[] rl)
 {
  for (Rechnungslauf__c rlf:rl)
  {
   Contract[] con;
   list<Rechnungspositionen__c> listrp = new list<Rechnungspositionen__c>();
   list<ProductLineItem_recurring__c> listpliupdate = new list<ProductLineItem_recurring__c>();
     
   // Select aller aktiven Verträge
   //******************************
   
   con = [select 
        id,
        AccountID,
        Rechnungsempfaenger__c     
     from contract 
     where 
     StartDate <= LAST_MONTH and      
     (Vertragsende_nfon__c >= LAST_MONTH OR Vertragsende_nfon__c = NULL)
     and Rechnung_manuell__c = false
     
     //zum Ausschluss von 0 Rechnungen
     //*******************************
     and Summe_netto__c !=0
     
     //Testrechnungslauf erstellen mit bestimmter ID (Hier Testaccount)
     //****************************************************************
     //and id ='80020000001Cdmu'
                
     //Einzelne Pakete erstellen
     //*************************
     //and ContractNumber >= '00000242'
     //and ContractNumber <= '00000243' 
     and ContractNumber >= :rlf.Vertragsnummer_von__c
     and ContractNumber <= :rlf.Vertragsnummer_bis__c     
    ];
     
      
   // For Loop zur Erstellung der Rechungen, Bezug auf die aktiven Verträge
   //**********************************************************************      
   for (contract connew:con)
   {
    // Definition neuer Variable zur Rechnungserstellung
    //**************************************************
    Rechnung__c r = new Rechnung__c();
      
    // Insert Rechnung - Relation to contractdata by variable 
    //*******************************************************        
    r.Firma__c = connew.AccountID;
    r.Rechnungsemail__c = connew.Rechnungsempfaenger__c;
    r.Rechnungslauf_ID__c = rlf.id;
    r.Vertrag_ID__c = connew.id;
    insert r;
     
    // Map für Lineitems mit Vertrags-ID und Status zum berechnen
    //***********************************************************
    map<id,ProductLineItem_recurring__c> plimap = new map<id,ProductLineItem_recurring__c>
    (
     [select Verkaufspreis__c,
       Menge__c,Discount__c,
       Listenpreis__c,
       Beschreibung__c,
       berechnet__c,
       MwSt__c,
         Vertrag__c,
       id     
      from ProductLineItem_recurring__c
      where next_RL_berechnet__c ='JA' 
      and Vertrag__c = :connew.id
     ]
    );
    
    //For-Loop zur Selektion der einzufügenden Items
    //**********************************************  
    for (ProductLineItem_recurring__c plis:[select Verkaufspreis__c,
        Menge__c,Discount__c,
        Listenpreis__c,
        Beschreibung__c,
        berechnet__c,
        MwSt__c,
          Vertrag__c,
        id     
      from ProductLineItem_recurring__c
      where id in :plimap.keyset()
      ]
     ) 
    {
     ProductLineItem_recurring__c plinew = plimap.get(plis.id);
     
     //Zurückschreiben des Datums der Rechnungsstellung
     //************************************************
     //plinew.berechnet__c = date.today();
                    //update plinew;
     
     //Abfrage ob die Liste =50 ist
     //****************************
     if(listrp.size() == 50)
     {
      insert listrp;
      listrp.clear();
     }
     
     //Hinzufügen zur Liste
     //********************
     listrp.add
     (
      new Rechnungspositionen__c
      (   
       Rechnungsnummer__c = r.id,
       Leistung__c = plinew.Beschreibung__c,
       Einzelpreis__c = plinew.Verkaufspreis__c,
       Discount__c = plinew.Discount__c,
       Listenpreis__c = plinew.Listenpreis__c,      
       Anzahl__c = plinew.Menge__c,
       MwSt__c = plinew.MwSt__c,
       Vertrag_ID__c = r.Vertrag_ID__c,
       recurring_Product_Line_Item_ID__c = plinew.id,
       Rechnungslauf_ID__c = rlf.id
       
      )
     );     
     
    }
    
    //For Loop zum Update des Berechnetdatums
    //***************************************
    for (ProductLineItem_recurring__c pliupdate:[select id,berechnet__c from ProductLineItem_recurring__c where id in :plimap.keyset()])
    {
     ProductLineItem_recurring__c pliupdatenew = plimap.get(pliupdate.id);
     
     //Abfrage ob die Liste =50 ist
     //****************************
     if(listrp.size() == 50)
     {
      update listpliupdate;
      listpliupdate.clear();
     }
     pliupdatenew.berechnet__c = date.today();
     listpliupdate.add
     (
     pliupdatenew
     );
    }
            
   }
   
   //Wenn die Liste noch Daten <50 enthält, werden diese hier eingefügt
   //******************************************************************
   if (listrp.size() >0) insert listrp;
   if(listpliupdate.size() >0) update listpliupdate;
 
  }
 } 
}

 But I still have Limitations:

Number of SOQL queries: 19 out of 20 ******* CLOSE TO LIMIT
Number of query rows: 111 out of 1000
Number of SOSL queries: 0 out of 0
Number of DML statements: 8 out of 20
Number of DML rows: 76 out of 100 ******* CLOSE TO LIMIT

gvgv

Hi

 

I have the same issue. I get the following error message

Error:Apex trigger syncOpportunitySalesGoal caused an unexpected exception, contact your administrator: syncOpportunitySalesGoal: execution of AfterUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id a0S70000001bFHAEA2; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, syncParentOpportunitySales: execution of AfterUpdate caused by: System.Exception: Too many DML rows: 138 Class.WorkflowTickler.TickleOpportunitySalesGoal: line 17, column 5 Trigger.syncParentOpportunitySales: line 6, column 3: Class.WorkflowTickler.TickleOpportunitySalesGoal: line 17, column 5

 

Does that mean 138 rows are getting updated . This code has been in production for a long time ad working fine too. But when a user was updating an oportunity is when this error came up 

 

This is the code

 

   for(Opportunity_Sales_Goal__c opportunitySalesGoal:opportunitySalesGoalArr) {

      opportunitySalesGoal.Last_Sync_To_Parent__c = currentTime;     

    }

    

    update opportunitySalesGoalArr;

  } 

 

If I comment the update statement the error does not occur. How do I get rid of this error.

 

Thanks 

Volker_factory42Volker_factory42
You could try this:

for(List<Opportunity_Sales_Goal__c> opportunitySalesGoal:OpportunitySalesGoalArr) {

opportunitySalesGoal.Last_Sync_To_Parent__c = currentTime;

}



update opportunitySalesGoalArr;

}

 

This is going through a bulk of 200, and is like query more. OpportunitySalesGoalArr should also be a list, to store all data. It's also important if a class from i.e. VF or a trigger is using this code (See Limitation...)
Message Edited by Volker_SF42 on 07-15-2009 12:00 AM
gvgv

Hi Volker

 

Thanks for the reply. When I change it to List as you suggested I get,  the following error

 

 Save error: Initial term of field expression must be a concrete SObject: LIST:SOBJECT:Opportunity_Sales_Goal__c

 

The  opportunitySalesGoalArr is an array.

 

This is how the whole method looks

 

public static void TickleOpportunitySalesGoal(Opportunity_Sales_Goal__c[] opportunitySalesGoalArr) {

    

    DateTime currentTime = System.Now();

    for(List<Opportunity_Sales_Goal__c> opportunitySalesGoal:opportunitySalesGoalArr) {

      opportunitySalesGoal.Last_Sync_To_Parent__c = currentTime;     

    }

    

    update opportunitySalesGoalArr;

  }

 

 

Thanks