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
sgkmillssgkmills 

Write a future call (async method) to avoid the System Exception Too many DML rows issue

I have a trigger that calls a asynchronous method and it hits the 'Too Many DML rows' exception.  Basically the trigger creates a bunch of records in a child table which is used to do statistics.  Is there any way that I can create these records at a later date, for instance schedule a job, or write a class to do the creation after the trigger completes.

 

I had a solution, but it entails in making numerous calls to the asynchrounous method.  When I do that, I hit the barrier of 'Too many Future Calls'

 

So my main question is how can I break the process up so I can load the DML rows into the child table.  BTW, the code is already batching the records and I have optimized the code for bulk operation.

 

Any ideas/help will be appreciated.

 

Thanks

Best Answer chosen by Admin (Salesforce Developers) 
aalbertaalbert

How many rows are you trying to created or update in the @future async method?

 

In the Summer '09 release, a limited release feature called Batch Apex is being released. More information here

This feature might solve your problem where you can execute larger scale apex processes in asynchronous fashion. It depends on the requirements and data/processing volumes.

 

All Answers

aalbertaalbert

How many rows are you trying to created or update in the @future async method?

 

In the Summer '09 release, a limited release feature called Batch Apex is being released. More information here

This feature might solve your problem where you can execute larger scale apex processes in asynchronous fashion. It depends on the requirements and data/processing volumes.

 

This was selected as the best answer
sgkmillssgkmills
The record count varies, it depends on the parent.  Basically, around 12,000 records get inserted between two tables that are associated to the object that initiated the trigger.  The first object is a child of this object (A), and the second is linked as a lookup of the first object
sfdccoder1sfdccoder1

You can wait for Summer 09 release and use "Batch Apex" (see http://blog.sforce.com/sforce/2009/05/batch-apex-a-powerful-new-functionality-in-summer-09.html) or ask for it as it is in preview mode now or you can use an alternative method for now:

 

A method for asynchronous mass DML in portions:


The idea is to have the trigger not to execute the business logic but rather to store meta data regarding the update and execute it later in portions smaller or equal to the governor limits using a batch script (see http://gokubi.com/archives/daily-cron-jobs-with-apex).

 

Let's take a look at an example. Say I have accounts with hundreds of contacts each and I need to update the contacts phone after the account phone changes (not a very realistic example but it clarifies things).

 

For this I need to create:

 

 a. A utility object which will hold:

 

     1. The update information (in this case the new phone number).

     2. A lookup field for the account.

     3. A status pick list field with two values: “Done updating contacts” , “Not done updating contacts”.

 

 We will name this objectAccount Update Helper” (API name Account_Update_Helper__c).

 

 b. A custom Account_Update_Helper__c lookup field in the Contact object. We will name itLast Account Update Helper” (API name Last_Account_Update_Helper__c).

 

When an account phone gets updated the trigger will create aAccount Update Helperrecord with:

 

 a. Phone = new account phone.

 b. Status = “Not done updating contacts”.

 c. Account = the related account.

 

The batch script will run at the maximum possible frequency  and will query the oldest* Account_Update_ Helper__c record with Status = “Not done updating contacts”**.

 

It will than query for a maximum of 99 related contacts with Last_Account_Update_Helper__c <> current Account_Update_Helper__c *** and update:

 a. Phone = “Account_Update_Helper__c.phone

 b. Last_Account_Update_Helper__c = current Account_Update_Helper__c Id (so we'll know not to update it in the next batch script execution).

 

In case there are no more records  to update we set Account_Update_Helper__c.Status__c = 'Done updating contacts'.

 


* Querying the 'oldest' Account_Update_Helper__c insures that when an account gets updated more than once and before all its contacts where updated, the updates will continue in chronological order and most important - the last update will reflect the last account update.

 

**  Filtering results with Status = “Not done updating contactsguarantees we are only updating contacts related to a Account_Upate_Helper__c which represents contacts which where not yet updated.

 

 *** Setting this filter: Last_Account_Update_Helper__c <> current Account_Update_Helper__c guarantees we only update contacts that where not already updated as a result of an account phone updated represented by the current Account_Update_Helper__c record.

 

HTH


Message Edited by sfdccoder1 on 05-18-2009 01:05 AM
sgkmillssgkmills

The metadata approach sounds interesting, but the "Batch Apex" would be perfect for my needs.  I guess I will check with salesforce to see if we can get it turned on in our sandbox so I can do some coding/testing

 

Thanks for the response and information answer.