So many DML rows, so few DML statements

Let me start by apologizing for the uber-geeky title to this post. We debated between other titles like Apex to the Future, and 100 rows of DML on the wall, but opted for one that would yield higher rankings in a search.

Lately, we’ve been getting a lot of Too Many DML Rows errors from existing code that used to work just fine. This is due to a recent change in the Apex Governor Limits. You can now only process 100 records via a DML statement per triggered record (Note that is 100 records total, not 100 per DML statement). In english, that means if you have a trigger that updates all Contacts on an Account when that Account is edited, you’ll get an error if there are more than 100 Contacts on that Account. This is a huge issue for some of us who have code that performs mass updates on records.

The good news is that there already is a documented solution that you can use to get around this. The @future annotation on an apex method has higher governor limits and we’ve found it to be a fairly simple process to update methods to use it. Start by adding the @future annotation to the line just before your method in your Apex Class. Then be sure to add the static annotation to your method. If your method only receives parameters that are primitive such as Ids, Strings, Integers, etc. then you may be done. If your method receives sObjects like Contacts, Accounts, etc, then you have to change them to receive Ids instead. Then, add a line to query for the records with those Ids. See the example below for more details.

The result is you get to update up to 10,000 records but the update occurs asynchronously, not immediately, so users expecting to see a change on the screen may get confused. Essentially you are just treating apex methods as asynchronous web services that are run on the salesforce servers. Now, we only wish we could schedule when in the future we want this method to run. When that feature arrives, maybe I’ll get to title the post Apex to the Future Part II

Old Method which will break if more than 100 contacts are being updated

public void updateContactOwner(Account[] accs){
Map<Id,Account> accountMap = new Map<Id,Account>();
for (Account a : accs ) {
accountMap.put(a.Id,a);
}
List<Contact> contactUpdates = new List<Contact>();
for ( Contact c :[Select Id, AccountId from Contact where AccountId in : accountMap.keySet()] ){
c.OwnerId = accountMap.get(c.AccountId).OwnerId;
contactUpdates.add(c);
}
if ( contactUpdates.size() > 0 ) {
update contactUpdates;
}
}

New Method which will update up to 10,000 contacts (although lists are limited to 1000 records, so some additional code is needed to get it to work on 10,000 records)

@future
public static void updateContactOwner(Id[] accIds) {
Map<Id,Account> accountMap = new Map<Id,Account>([Select Id, OwnerId from Account where Id in :accIds]);

List contactUpdates = new List();
for ( Contact c : [Select Id, AccountId from Contact where AccountId in : accountMap.keySet()] )
{
c.OwnerId = accountMap.get(c.AccountId).OwnerId;
contactUpdates.add(c);
}
if ( contactUpdates.size() > 0 )
{
update contactUpdates;
}
}

  • Share/Bookmark

Related posts:

  1. My new best friend
  2. Composite Application Case Study
  3. Dynamic Picklist Creation and Sorting
  4. Update Record Types from the Edit Page
  5. Properly Formatting Names in Apex

One Comment to “So many DML rows, so few DML statements”

  1. GunishNo Gravatar Says:

    Hey,
    Your Solutions Says there is an List of type, in Future classes,

    List contactUpdates = new List();

    This throws an error,
    anothe issue is, that this has to be a static to be future.

    Would you suggest alternative solutions ?

    Thanks,
    Gunish

Post a Comment