+ Start a Discussion
kottegronkottegron 

Too many retries of batch save in the presence of Apex triggers with failures

Hi everyone!

I'm trying to validate a Event field with a trigger. I'm using a trigger because it's dependent on values in the Account object. I want to show the user an error with sObject.addError() method. The test scenarios in the Salesforce GUI for 1 record at a time is working fine however the test class is failing. I'm creating 200 event records and inserting them at the same time. 

/*test class*/
try{
insert eventList;
 }
catch (Exception e) {
System.assert(e.getMessage().contains('The error message that should be shown'), e.getMessage());
 }

/*Event handler method*/
public void displayErrorMessage(List<Account> accountList){
      for (Account acc : accountList){
             if(acc.Type == 'Agency')
                eventMap.get(acc.Id).WhatID.addError('The error message that should be shown', false);
      }
}

/*Trigger*

trigger EventBefore on Event (before insert, before update) {
      if(Trigger.isInsert || Trigger.isUpdate){
          Event_TypeOfMeetingHandler handler = new Event_TypeOfMeetingHandler( trigger.new );
      }
}

THIS IS THE ERROR MESSAGE I'M GETTING:

 
Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, Too many retries of batch save in the presence of Apex triggers with failures: when triggers are present partial save requires that some subset of rows save without any errors in order to avoid inconsistent side effects from those triggers. Number of retries: 2: []

THE TEST WORKS FINE FOR THE FOLLOWING TRIGGER CODE. INSERT ONLY THOUGH.  
trigger EventBefore on Event (before insert) {
      if(Trigger.isInsert){
          Event_TypeOfMeetingHandler handler = new Event_TypeOfMeetingHandler( trigger.new );
      }
}

What am I doing wrong in the Trigger handler alternative what can I do in the test class to make this work for multiple insert and updates on  Event records? 

Thanks!

Best Answer chosen by kottegron
Alexander TsitsuraAlexander Tsitsura
Hello,

This exception arises from a bulk DML call. 

For more detail about "Bulk DML Exception Handling", please follow the link: 
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dml_bulk_exceptions.htm

My thought about a bug that causes the exception. Please looks at line:
eventMap.get(acc.Id).WhatID.addError('The error message that should be shown', false);

Is it possible that one an account has many events? If yes, then you need to rewrite a validation logic.
// get all account ids
Set<Id> whatIds = new Set<Id>();
for (Event e : eventsList) {
    accountIds.add(WhatId);
}

// query all Accounts
Map<Id, Account> accountsMap = [
    SELECT Id, Name
       FROM Account
      WHERE ID IN :whatIds
]; 

// validate events
for (Event e : eventsList) {
    if (accountsMap.containsKey(e.WhatId)) {
        Account a = accountsMap.get(e.WhatId);
        if (a.Name == 'Agency') {
            e.WhatID.addError('The error message that should be shown', false);
        }
    }
}

If it helped you, then please select it the best answers it will help outer also.

Thanks,
Alex

All Answers

Alexander TsitsuraAlexander Tsitsura
Hello,

This exception arises from a bulk DML call. 

For more detail about "Bulk DML Exception Handling", please follow the link: 
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dml_bulk_exceptions.htm

My thought about a bug that causes the exception. Please looks at line:
eventMap.get(acc.Id).WhatID.addError('The error message that should be shown', false);

Is it possible that one an account has many events? If yes, then you need to rewrite a validation logic.
// get all account ids
Set<Id> whatIds = new Set<Id>();
for (Event e : eventsList) {
    accountIds.add(WhatId);
}

// query all Accounts
Map<Id, Account> accountsMap = [
    SELECT Id, Name
       FROM Account
      WHERE ID IN :whatIds
]; 

// validate events
for (Event e : eventsList) {
    if (accountsMap.containsKey(e.WhatId)) {
        Account a = accountsMap.get(e.WhatId);
        if (a.Name == 'Agency') {
            e.WhatID.addError('The error message that should be shown', false);
        }
    }
}

If it helped you, then please select it the best answers it will help outer also.

Thanks,
Alex
This was selected as the best answer
kottegronkottegron
Fantastic Alexander!

That solved my problem

Cheers