0

I've been using addError() to prevent dml insertions of records that don't accomplish with the validation rule. The problem is that using that, if i insert a list of 100 records and one fails, the other 99 doesn't get inserted because i receive the next exception:

EXCEPTION_THROWN|[24]|System.DmlException: Insert failed. First exception on row 1; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION

There is any way to catch the exception ort an alternative that allows me to insert all the records that don't fail?

Here is the code:

public void bulkBefore() {

    if((Trigger.isInsert && !Trigger.isDelete) || Trigger.isUpdate){

        for(GPMIR_obj_energyLead__c l : (List<GPMIR_obj_energyLead__c>)Trigger.new) {

            if(l.GPMIR_fld_codigoOrigen__c == null || (l.GPMIR_fld_phone__c == null && l.GPMIR_fld_email__c == null)){
                l.addError('Error en la inserción. El origen, el canal y el teléfono o Email tienen que estar informados');
                lstLeadDigitalRecIncom.add(l);
            }else{...}

public void beforeInsert(SObject so) {
        String errorMessage;
        GPMIR_obj_energyLead__c eLead = (GPMIR_obj_energyLead__c) so;

        if(lstLeadDigital.contains(eLead)){
            if(lstLeadDigitalRecIncom.isEmpty() || !lstLeadDigitalRecIncom.contains(eLead)){
                eLead.RecordTypeId = rtDigitalId;
                if(eLead.GPMIR_fld_generationDate__c == null){
                    eLead.GPMIR_fld_generationDate__c = Date.today(); 
                }
                lstSobjLeadDig.add((sObject)eLead);
            }else{
                eLead.RecordTypeId = rtDigitalId;
            }
        }else{...}

I would really appreciate any help :)

1 Answer 1

4

The decision of whether to allow partial success - permitting the 99 to go through to the database, while the 1 fails and is rejected - lies with the code that initiates the DML rather than with the trigger itself. Once the operation gets to the trigger, that decision has been made.

The key distinction is how the caller initiated the operation. If they ran a simple DML operation:

List<Contact> contacts = ...
insert contacts;

That's an all-or-none operation by default: either every record succeeds and is committed, or the whole operation is rolled back with a DmlException.

The caller has a choice, though. By instead initiating DML through the Database class (or configuring DMLOptions, they can use methods like Database.insert(), which take a second parameter allOrNone.

public static Database.SaveResult[] insert(sObject[] recordsToInsert, Boolean allOrNone)

Specify false for the second parameter to allow partial success, and inspect the return value (Database.SaveResult[]) to determine which specific records succeeded or failed. Specifying true will yield the same exception-plus-rollback behavior as a regular DML operation.

It's important for this decision to live outside the trigger, because only the caller is likely to know whether allowing partial success will leave the database in a sensical state. While the platform won't allow you to do things that violate schema-level constraints (like failing to populate a master-detail field), the question of "Are the 99 records meaningful without the 1?" can likely only be answered by the code that's attempting to create them.

2
  • That David, is the best answer i've ever received. The problem is that records are going to be inserted in Salesforce via POST callout from an external web service, so i don't know how to control that. I'm pretty new by the way :) Jul 22, 2019 at 21:03
  • @HéctorCerveraPanella What kind of API endpoint is the web service hitting? Standard sObject Create only does one record at a time; if you're using a custom Apex REST endpoint or the Collections endpoint or the Bulk API, different solution patterns would apply.
    – David Reed
    Jul 22, 2019 at 21:06

You must log in to answer this question.

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