4

I would like to insert list of records, catch various exceptions, and if the exception is something I can't handle send the offending objects for manual processing.

I can write most of what I need, but one thing has me stumped, the return information in the SaveResult class after a Database.Insert.

There is a similar question with an accepted answer, however the ID is null so there is not a way to access the object that failed to be inserted. How to capture those records that was unable to get inserted?

From the documentation on SaveResult and Exception handling:

SaveResult

Into To Exception Handlign

SF shows:

Database.insert(contacts, false);

Which returns the SaveResult. However the only methods available in the SR are:

  • getErrors()
  • getId()
  • isSuccess()

None of these help on determining the records that fail on an insert. getErrors provides additional error reporting about the exact error, getId only works on updates, isSuccess is a boolean.

The code below demonstrates my issue:

Account a = new Account(Name = '');
Database.SaveResult SR = Database.insert(a, False);
System.debug('SaveResult: ' + SR);

Debug:

DEBUG|SaveResult: Database.SaveResult[getErrors=(Database.Error[getFields=(Name);getMessage=Required fields are missing: [Name];getStatusCode=REQUIRED_FIELD_MISSING;]);getId=null;isSuccess=false;]

Is there a way to access the failed records on an insert? One thought I had was if there is a failure loop though the original list and weed out the ones that have an ID and handle the exceptions that way. But I think that would get tedious with loop after loops as I try to handle the exceptions and continue to have failures.

UPDATE: As a proof of concept for the above

List<Account> accs = new List<Account>();
Account a = new Account(Name = 'TestingAccOne');
Account b = new Account(Name = '');
accs.add(a);
accs.add(b);
Database.SaveResult[] SR = Database.insert(accs, False);
System.debug('SaveResult: ' + SR);
System.debug('accs: ' + accs);

Debug: SR:

USER_DEBUG [7]|DEBUG|SaveResult: (Database.SaveResult[getErrors=();getId=001R000000sLHNhIAO;isSuccess=true;], Database.SaveResult[getErrors=(Database.Error[getFields=(Name);getMessage=Required fields are missing: [Name];getStatusCode=REQUIRED_FIELD_MISSING;]);getId=null;isSuccess=false;])

List:

USER_DEBUG [8]|DEBUG|accs: (Account:{Name=TestingAccOne, Id=001R000000sLHNhIAO}, Account:{Name=})

From the above I'm leaning toward removing all records from the above list with an ID and then can focus on the offending ones.

Any suggestions and input are greatly appreciated.

  • 1
    Yeah mapping partial save results on insert is pretty much impossible. On a try/catch at least you can figure out the DML Index. – Adrian Larson Apr 23 '15 at 20:07
  • True, the main reason I went with the Database.Insert was to allow the ones that succeeded to go through. However after looking at the exception class methods as you mentioned I could Try/Catch and determine the dml index, handle those separately and they try another insert at the ones that didn't fail the first time. If they succeeded once, they 'shouldn't' fail the next time. – Ricky Hewitt Apr 23 '15 at 20:32
7

There is no actual record to get if the insert fails, and no ID available as the record was never created. What you can do is loop through the resultset, and look at other attributes of your records. The List you are inserting will be in the same order as the resultset. So, you could do something like this:

List<Account> accs = new List<Account>();
Account a = new Account(Name = 'TestingAccOne');
Account b = new Account(Name = '');
accs.add(a);
accs.add(b);
Database.SaveResult[] SR = Database.insert(accs, False);
System.debug('SaveResult: ' + SR);
System.debug('accs: ' + accs);

for(Integer i=0;i<SR.size();i++){
    if(!SR[i].isSuccess()){//only look at failures, or NOT Successes
      system.debug(SR[i]. getErrors()));
      system.debug(accs[i]); //instead of debug, you could have an email processor something else that looks at that record and the error message
    }
}
|improve this answer|||||
  • 'The List you are inserting will be in the same order as the resultset'. Is there documentation that supports this? I would hate to write something solely based on the order of the list only to find that it the order is the same 90% of the time. – Ricky Hewitt Apr 24 '15 at 19:41
  • Yes, this is stated in the documentation. salesforce.com/us/developer/docs/apexcode/Content/… – JimRae Apr 24 '15 at 21:06
  • Must have missed that when I was reading the documentation initially. This is a little cleaner than what I was going to do and from the documentation is SF's recommended way to handle this problem. Thanks @JimRae – Ricky Hewitt Apr 27 '15 at 14:42
1

getId() would return a value only when the DML is a success. There is no way to Id of the object that was never inserted.Even if you use try/catch block to get the Id, the result would be null. getDmlId() method of DMLException class returns Id of the failed record (only when the Id already exist).

|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.