2

I'm trying to write a trigger and having some real trouble in making it work.

Background: we adopted the Country/State picklist "Feature" last year. All the cleanup wasn't done. We have some records that currently violate the validation rule.

Trigger: my trigger is one that updates a contact when it's lookup account is changed. Basically, I have a field on the account and contact that mirrors, with the one at the account level taking prescedence. (Trigger on Account (after insert, after update))

Problem: If the contact has invalid country/state values, then the field validation exception is thrown when using DML statement.

update accounts;

This isn't a problem for one-offs, but has obvious problems during bulk update/insert.

Question: So, I've decided to allow a partial update. Here's the code (pretty boiler plate from what I've seen):

    Database.SaveResult[] lsr = Database.update(updateContacts, false);  
 for(Database.SaveResult sr : lsr){
    if (!sr.isSuccess()) {
        for(Database.Error err : sr.getErrors()) 
        {
            System.debug('The following error has occurred' + sr.getId());               
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Account fields that affected this error: ' + err.getFields());
        }
    } 
}

Now, when I implement this, the field validation exception is no longer thrown (or is handled somehow) and all the records update without fail.

Does this sound right? Is there a way that the database class somehow avoids the validation error that dml statements are subject to?

Any advice would be helpful. Thanks in advance.

  • With the above method, not all contacts are guaranteed to be updated when you update their parent. Why don't you just turn off the validation rule if it is not according to the business rule? If you want the validation rule to be fired while record update, there is not other way than cleaning your dirty records. – Shailesh Patil Mar 18 '15 at 17:18
4

Not all records will be updated. It is a partial update. You're ignoring the errors (there's no addError function), so they silently disappear.

You'll want something like this:

Map<Id, Account> accounts = new Map<Id, Account>();
Map<Id, String> errors = new Map<Id, String>();

// Prepare data
for(Contact record: Trigger.new) {
    if(record.AccountId != null) {
        accounts.put(record.AccountId, new Account(Id=record.AccountId /* etc... */));
    }
}

// We need an ordered list
Account[] accountList = accounts.values();
Database.SaveResult[] saves = Database.update(accountList, false);

// Process errors
for(Integer index = 0; index < saves.size(); index++) {
    if(!saves[index].isSuccess()) {
        errors.put(accountList[index].Id, saves[index].getErrors()[0].getMessage());
    }
}
// Report errors to related contact
for(Contact record: Trigger.new) {
    if(errors.containsKey(record.AccountId)) {
        record.addError('Failed to update account: '+errors.get(record.AccountId));
    }
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.