2

I do not wish to paste the HUGE trigger this is related to (several hundred lines). However, a long time ago when it was first written, I believe it was MEANT to update "all accounts affected" with ONE "update" command at the end, while right now, it's executing "update" after each account (which I believe is attributing to the very limited number of records that can be touched in a single batch, between 10 and 50).

update accObj;

//updateList.add((Account)accObj);

The first line is currently executed after each Account is processed. I BELIEVE the second line was previously used to accumulate "all accounts to run update against" so that you could then "update" AFTER ALL accounts were done being touched. I cannot find reference to how I'd notate the "update" command if this is true. I am imagining it is something like:

update (updateList);

Could someone verify? I don't want to trial-and-error this, find out it sort of works, deploy it and... cause issues by virtue of an ASSumption.

Thanks.

3 Answers 3

3

You are correct, you can just call update with the list as a paramter:

update updateList;

And if you want to prevent one failed record from stopping all the others you want to use the Database methods (the method can fail all if you require it to do so, see the docs):

for(Database.SaveResult r = Database.update(updateList, false)
{
    if(!r.isSuccess())
    {
        // error handling - you can use addError() to add errors to individual records
    }
}

A final thing to consider is whether you need to allow for more than 200 updates. For example, if your trigger is not working on the Account object directly, you may have more than 200 accounts which need updating and this can not be done in one update. In that scenario you need to modify the code where you add the accounts to the list (I'm using the simple style update for brevity):

for(Account accOjb : <<some account collection>>)
{
    // inside a loop
    updateList.add(accObj);

    if(updateList.size() == 200)
    {
        update updateList;
        updateList.clear();
    }
}

// outside the loop, need to see if there are any left-overs:
if(updateList.size() > 0)
{
    update updateList;
}
4
  • 1
    In apex salesforce automatically handles splitting large DML operations into multiple batches seamlessly. Unlike API clients you can do a 10,000 row DML statement and it will work seamlessly. Commented Oct 17, 2012 at 23:36
  • Oooh, when did we get that? Awesome!
    – Matt Lacey
    Commented Oct 18, 2012 at 0:51
  • 1
    Thanks a million. Stack Exchange is so insanely helpful (thanks to everyone who contributes). ;)
    – AMM
    Commented Oct 18, 2012 at 14:16
  • Your third code sample, in actuality, is HUGELY helpful, and may possibly end my miserable 1-45 record max batch size issue when using DataLoader with our Opps (the Opps trigger does a massive check and update to the Account)!
    – AMM
    Commented Oct 18, 2012 at 14:19
2

The normal update keyword works on lists/arrays of sObjects as well as single objects. So something as simple as:

update updateList;

Should work just fine. There's also an alternate method syntax like so:

Database.update(updateList);

This second from has some optional parameters relating to advanced DML options (not usually relevant, they control things like assignment rules) and allows allowing partial saves, but both bits of my sample code are equivalent and should behave exactly the same.

0
2

You are most likely running into governor limits as a result of including a DML statement within a loop. Currently you can issue 150 DML statement within an invocation context.

The best practices for triggers include keeping all queries and DML statements outside of any loops. Your code should only perform a query, update, etc once per invocation and should not be dependent on the number of records in your batch. (Here is a pretty good blog post ).

It looks like from the excerpt you provided that the code was originally set up to according to these best practices, but something changed over time.

List<Account> updateList = new List<account>();
for (Account accObj : UniverseOfAccounts) {
   //Where UniverseOfAccounts is the list of accounts you are looping over in your trigger
   if (meetsSomeCondition(accObj)) {
      // you have some logic here to change some field values on the account
      accObj.someField = someNewValue;

      // now add it to your list to be updated outside of the loop
      updateList.add(accObj);
   }
}


// now perform the actual update
if(updateList.IsEmpty()==false) {
    update updateList;
}

I would make sure to do some testing with real data before deploying, since I'm guessing some issue came up somewhere else in the code that caused the developer to shift from doing things the right way from a bulk perspective. Perhaps one of the records would fail in the batch due to a validation rule or some other problem and prevent all the updates from occurring? If that is the case look into some exception handling around the update (see the example at the bottom of the page for inspiration) and perhaps the optAllorNone property as a better solution than having the update within a loop.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .