4

I need to check if a record which is getting inserted has a duplicate. If there is one, then change a boolean field (Is_latest__c) to true in the inserted record and update the duplicate's field to false. I have created a before insert trigger, and in this trigger I check if a duplicate exists and change the Is_latest__c field of the inserted record to true. But when I try to update the old duplicate value in the trigger I am getting error that

System.DmlException: Update failed. First exception on row 0 with id afdfd9000000hxuSAEAY; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, lastupdate: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id arfg45000000hxuSAEAY; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = artr9000000hxuSA) is currently in trigger lastupdate, therefore it cannot recursively update itself

Is there any solution for this issue?

My code:

trigger lastupdate on Visit__c(before insert, before update) {
    if(Trigger.isBefore) {
        visitTriggerHandler vTH = new visitTriggerHandler();
        vTH.beforeInsertTrigger(Trigger.new);
    } 
}

public class visitTriggerHandler {
    public Set<String> contactFieldSet = new Set<String>();
    public Set<String> projectFieldSet = new Set<String>();
    public Set<String> surveyFieldSet = new Set<String>();
    public List<Visit__c> visitList = new List<Visit__c>();
    Map<Id, Visit__c> visitBeforeInsertMap = new Map<Id, Visit__c>();

    public void beforeInsertTrigger(Map<Id, Visit__c> visitBeforeInsertMaps, List<Visit__c> visitBeforeInsertList) {
        for(Visit__c visitToMap : visitBeforeInsertList) {
            visitBeforeInsertMap.put(visitToMap.Id, visitToMap);
        }

        for(Visit__c visit : visitBeforeInsertList) {
            contactFieldSet.add(visit.Contact__c);
            projectFieldSet.add(visit.Project_Group__c);
            surveyFieldSet.add(visit.Survey__c);
        }

        visitList = [SELECT Id FROM Visit__c
                     WHERE Survey__c IN :surveyFieldSet
                     AND Contact__r.Id IN :contactFieldSet
                     AND Project_Group__c IN :projectFieldSet
                     AND Is_latest__c = true];

        if(visitList.size() > 0) {
            for(Visit__c islastUpdate : visitBeforeInsertList) {
                islastUpdate.Is_latest__c = true;
            }
        }

        //visitList.add(islastUpdate);
        visitBeforeInsertList = visitBeforeInsertMap.values();
        //update visitList;
    }
}
1
  • 2
    this can have different causes. Pls include your code so we can provide the right answer. Nov 27, 2014 at 13:06

2 Answers 2

4

In a before update you don't need to explicitly call update on the records you want to modify. You're working on them before they go into the database, so you simply need to set the field values you want and that's it.

trigger smithification on Contact (before insert, before update) {
   if(Trigger.isBefore)
      for(Contact c : Trigger.New)
         c.LastName = 'Smith';
}

The above trigger would mean all contacts currently being modified in the system have the last name 'Smith'.

3
  • yes you are right. But here I need to update a old record when new duplicate recode is create it mean only on before insert. So that is way I am getting confused that same time when I insert a record I need to update to.
    – Anu
    Nov 28, 2014 at 5:27
  • If you're updating an old record, that will then fire the trigger again (as update). You'll want to use a static boolean or similar to prevent the trigger running a second time.
    – Matt Lacey
    Nov 28, 2014 at 6:30
  • yes but how can I update a old record in before insert. Because in before insert it is not allowing to update any record which is existing in data base.
    – Anu
    Nov 28, 2014 at 6:49
3

First, by definition, all of the records inserted in the before insert trigger should be set to isLatest__c = true

So, your problem is how to set the records with the same value of survey, contact.id, and project_group to isLatest__c = false

I would break up this problem into two triggers - one before insert and one after insert (actually, I would use a trigger framework and just have different handlers for each trigger entry point but that is a longer discussion)

The before trigger

trigger isLatestUpdate on Visit__c (before insert) {
  for (Visit__c v : Trigger.new) 
     v.isLatest__c = true;  // implicitly sets the value of field in all members of trigger list to true
}

The after trigger

trigger isNoLongerLatestUpdate on Visit__c (after insert) {
 Set<ID> contactIdSet = new Set<ID>();
 Set<String> surveySet = new Set<String>();
 Set<String> projGpSet = new Set<String> ();

 // Step 1 - build sets needed to query other Visits
 for (Visit__c v : Trigger.new)  {
    contactIdSet.add(v.contact__c);
    surveySet.add(v.survey__c);
    projGpSet.add(v.project_group__c);
 }

// Step 2 - query for all other Visits (be sure not to query ourself) with matching survey/contact/proj gp
 List<Visit__c> noLongerLatestVUpdList = new List<Visit__c> ();
 for (Visit__c otherV : [select id, survey__c, contact__c, project_group__c 
                         from Visit__c 
                         where survey__c IN :surveySet and contact__c IN :contactSet and
                           project_group__c IN :projGpSet and id not IN :trigger.newMap.keySet()]) {
    otherV.isLatest__c = false;
    noLongerLatestVUpdList.add(otherV);
 }

// Step 3 - update the no longer latest Visits
 try {
  update noLongerLatestVUpdList ;  // You could also do database.update(noLongerLatestVUpdList ,false) if you want to allow for partial successes in fixing up the old Visit__c
 }
 catch (DmlException e) { // do something useful here including, optionally, rolling back the transaction }

Code was typed in -- might have compile errors

You must log in to answer this question.

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