-2

Help me to solve this problem:

When inserting a new record, title field must be updated to 'Demo for After insert'. When updating the record, the title must be updated into 'Demo for After Update'.

trigger AfterInsertDemo on Contact (after insert,after update) {
    List<contact> conlist=new List<contact>();
    if(Trigger.isAfter && Trigger.isInsert){
        for(Contact con : Trigger.new){
            Contact obj = new Contact(Id = con.Id);
            if(con.LastName !=null){
                obj.Title='Demo for After Insert';
            }
            conlist.add(obj);
        }
    }
    if(Trigger.isAfter && Trigger.isUpdate){
        for(Contact con : Trigger.new){
            Contact obj = new Contact(Id = con.Id);
            if(con.LastName !=null){
                obj.Title='Demo for After update';
            }
            conlist.add(obj);
        }
    }
    update conlist;
}
2
  • 4
    Welcome to SFSE. The purpose of updating the title is not very clear but this should be done in a before trigger event because you want to update fields on record fired by the trigger. Depending on your requirement, record triggered flows can be a better option instead of apex triggers trailhead.salesforce.com/en/content/learn/modules/…
    – Shamina
    Jul 2 at 5:50
  • Please check out help center and How to Ask, then edit your post to describe the specific problem with this code.
    – David Reed
    Jul 2 at 16:11

2 Answers 2

1

Reason: Recursive Trigger

There are so many methods to handle the Recursive Trigger issue.

Reference link:

Recursive Trigger Handlers

Check the code changes below.

trigger AfterInsertDemo on Contact(after insert, after update) {

  List < contact > conlist = new List < contact > ();
  if (Trigger.isAfter && Trigger.isInsert) {

    for (Contact con: Trigger.new) {
      Contact obj = new Contact(Id = con.Id);
      if (con.LastName != null) {
        obj.Title = 'Demo for After Insert';
      }
      if (!ContactRecursiveHandler.alreadyProcessedIdSet.contains(con.Id)) {

        conlist.add(obj);
        ContactRecursiveHandler.addToProcessed(con.Id);
      }
    }

  }

  if (Trigger.isAfter && Trigger.isUpdate) {

    for (Contact con: Trigger.new) {
      Contact obj = new Contact(Id = con.Id);
      if (con.LastName != null) {
        obj.Title = 'Demo for After update';
      }
      if (!ContactRecursiveHandler.alreadyProcessedIdSet.contains(con.Id)) {

        conlist.add(obj);
        ContactRecursiveHandler.addToProcessed(con.Id);
      }
    }
  }

  update conlist;

}

/ Need to create a new apex class to handle recursive /

public class ContactRecursiveHandler {

  public static Set < Id > alreadyProcessedIdSet;

  public static void addToProcessed(Id contactId) {

    if (alreadyProcessedIdSet == NULL) {
      alreadyProcessedIdSet = new Set < Id > ();
    }
    alreadyProcessedIdSet.add(contactId);
  }
}
1
  • AfterInsertDemo: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.AfterInsertDemo: line 27, column 1 this error occured during update record and same error occured for insert the new record in line 11. Jul 4 at 5:29
0

As Naveen has pointed out - you are running into a recursion issue.

When your trigger updates a Contact, that Contact record invokes the trigger in the after update context. The trigger then assigns the Title field and tries to update it again. It then just keeps repeating this until it hits the recursion limit of 16 recursions (I think).

So, to fix it, you need to fix your recursion issue.

For this class, it looks like it's just a demo, but I'll mention this just in case - you should handle field updates for records that invoke a trigger in before insert and before update events in almost all cases.

For this piece of code, a good way to stop recursion would be to check if Title has already been set, or if it has already been set to the value you're trying to set in the after update context.

    if(Trigger.isAfter && Trigger.isUpdate){
        for(Contact con : Trigger.new){
            Contact obj = new Contact(Id = con.Id);
            if(con.LastName !=null) {
                obj.Title='Demo for After update';
            }
            conlist.add(obj);
        }

to

    if (Trigger.isAfter && Trigger.isUpdate){
        for(Contact con : Trigger.new){
            Contact obj = new Contact(Id = con.Id);
            if(con.LastName !=null && con.Title != 'Demo for After update') {
                obj.Title='Demo for After update';
            }
            conlist.add(obj);
        }

Something like that.

How you deal with recursion issues can vary greatly depending on what you're doing and there are many methods. The main thing is to understand what recursion is and why it happens (have a look at some different examples of it too). Then, in the future when it pops up in a real use-case, you'll be able to identify the most appropriate method of dealing with it!


Also, I want to point out:

Contact obj = new Contact(Id = con.Id);

Since you already have the SObject you're wanting to update (the current loop variable con), you should just update its field directly, then add it to your list of things to update rather than creating a whole new SObject as that will take the CPU more time.

Instantiating a new SObject to make an update to an existing record is good for times where you ONLY have an ID and data, but no SObject already. (For example, an asynchronous method.)

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