Salesforce trigger hell-1

Problem

Many a time we see that the errors added by trigger's, are being shown to user in the below format, which are not user friendly and user's complain about that.

Error: Invalid Data. 
Review all error messages below to correct your data.Apex trigger validateLastname caused an unexpected exception, contact your administrator: validateLastname: execution of BeforeInsert caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, no child allowed: Trigger.validateLastname: line 6, column 1

Root cause

Whenever error with the line number is shown to user, you can be sure that this is un-handled exception. And it comes basically when you have fired another DML inside any trigger, and that DML is failed. 
Let's understand this by scenario.

Scenario

 Let's assume that User is trying to save a record of OBJ1 from User interface. and you have written a trigger on OBJ1, which on certain condition insert the record of OBJ2. there is one trigger on OBJ2 which blocks the record creation on certain condition. As shown below.

Trigger - 1
trigger triggerOnOBJ1 on OBJ1 ( after insert ) {
     if( Trigger.new[0].name == 'ABC' ){
            insert new OBJ2( name = 'XYZ' );
     }
}


Trigger - 2
trigger triggerOnOBJ2 on OBJ2 ( before insert ) {
    if( Trigger.new[0].name == 'XYZ' ){
        trigger.new[0].addError( ' name XYZ is not allowed ' );
}


Here Trigger1 tries to insert OBJ2, and invokes Trigger2. Now if Trigger2 'adds Error' then that will not be catched in the Trigger1 and User will directly recieve dirty message of exception. Which should be avoided.

The best practice is to handle the DML exceptions even inside the trigger.
better way of coding would be as follows, with the try/catch blocks.



Trigger - 1
trigger triggerOnOBJ1 on OBJ1 ( after insert ) {
     if( Trigger.new[0].name == 'ABC' ){
          try{
             insert new OBJ2( name = 'XYZ' );
          }catch( DMLException ex ){
             trigger.new[0].addError( ex.getDmlMessage(0) );
          }
     }
}

Trigger - 2
trigger triggerOnOBJ2 on OBJ2 ( before insert ) {
   if( Trigger.new[0].name == 'ABC' ){
      trigger.new[0].addError( ' name XYZ is not allowed ' );
}

BEST PRACTICE

Always write the code for worst case, Hence if you are writing any DML inside the trigger, catch the exception.
package tutorial;
      import com.opensymphony.xwork2.ActionSupport;
      public class HelloWorld extends ActionSupport {
       private String name;
       public String getName() {
       return name;
       }
       public void setName(String name) {
        this.name = name;
       }
       public String execute() {
        name = "Hello, " + name + "!"; 
        return SUCCESS;
       }
      }

Comments

Popular posts from this blog

Use the System.enqueueJob Method to Specify a Delay in Scheduling Queueable Jobs

Secure Apex Code with User Mode Database Operations (Generally Available)

IsVisibleInSelfService on Task salesforce