function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ckellieckellie 

Two Triggers Cannot Recursively Update Itself

I am working on an application where the user will create a custom object (mps) record from the opportunity and a trigger will update certain fields on the mps from the opportunity.When there is an MPS record attached to the opportunity, the opportunity will update the mps, and when the mps is updated, the opportunity is updated. This has created an error that says "...cannot recursively update itself..." I am trying to find a way to prevent this. The problem is I cannot the find a way to break this recursion.

 

I wannt both records to be updated when one record is updated. Below are my triggers:

 

 

trigger OppUpdateMPS on Opportunity (before update) {
       Map<Id, Id> mapOpportunitytoMPS = new Map<Id, Id>();

    for(Opportunity o : trigger.new){
        // Populate map of Opportunity.Id to MPS.Id
        if (o.MPS__c != null) {
            mapOpportunitytoMPS.put(o.Id, o.mps__c);
        }
    }

    if (!mapOpportunitytoMPS.isEmpty()) {
        // Query all relevant opportunities to a map with key of Opportunity.Id
        Map<Id, MPS__c> mps = new Map<Id,MPS__c>([select id, MPS_BV__c, MPS_Comment__c, 
                         MPS_Scheduled_Ship_Date__c, MPS_Status__c, Close_Date__c, LastModifiedDate,
                         Projected_Ship_Date__c, Projected_On_Site_Delivery_Date__c,
                         Forecast_Category__c, Combined_Probability__c, Recursive_Update__c
                         from MPS__c where id in:mapOpportunitytoMPS.values()]);

        List<MPS__c> mpsToUpdate = new List<MPS__c>();
        Id mpsId;
        MPS__c m;

        for (Opportunity s : trigger.new) {
            if (mapOpportunitytoMPS.containsKey(s.Id)) {
                // Get the MPS__c ID from the map
                mpsId = mapOpportunitytoMPS.get(s.Id);
                // Get the opportunity based on the opportunity ID
                m = mps.get(mpsId);
                // Set fields on MPS based on Opportunity
                m.Forecast_Category__c = s.ForecastCategoryName;
                m.Combined_Probability__c = s.Combined_Probability__c;
                m.Close_Date__c = s.CloseDate;
                m.Projected_Ship_Date__c = s.Projected_Ship_Date__c;
                m.Projected_On_Site_Delivery_Date__c = s.Projected_On_Site_Delivery_Date__c ;
                m.MPS_Scheduled_Ship_Date__c = s.MPS_Scheduled_Ship_Date__c;
                MPSToUpdate.add(m);
            }
        }

        // Update all MPS__c in one call
        update MPSToUpdate;
        
    }
}

 

trigger MPSUpdate on MPS__c (Before Insert, Before Update) {
    Map<Id, Id> mapMpsToOpportunity = new Map<Id, Id>();
     
    for(MPS__c mps : trigger.new){
        // Populate map of MPS.Id to Opportunity.Id
        if (mps.OpportunityID__c != null) {
            mapMpsToOpportunity.put(mps.Id, mps.OpportunityID__c);
        }
    }
    
    if (!mapMpsToOpportunity.isEmpty()) {
        // Query all relevant opportunities to a map with key of Opportunity.Id
        Map<Id, Opportunity> opps = new Map<Id, Opportunity>([select id, MPS_BV__c, MPS_Comment__c, 
                         MPS_Scheduled_Ship_Date__c, MPS_Status__c, CloseDate,
                         Projected_Ship_Date__c, Projected_On_Site_Delivery_Date__c,
                         ForecastCategoryName, Combined_Probability__c
                         from Opportunity where id in:mapMpsToOpportunity.values()]);

        List<Opportunity> oppsToUpdate = new List<Opportunity>();
        Id oppId;
        Opportunity o;
        for (MPS__c s : trigger.new) {
            if (mapMpsToOpportunity.containsKey(s.Id)) {
                // Get the opportunity ID from the map
                oppId = mapMpsToOpportunity.get(s.Id);
                // Get the opportunity based on the opportunity ID
                o = opps.get(oppId);
                // Set fields on MPS based on Opportunity
                s.Forecast_Category__c = o.ForecastCategoryName;
                s.Combined_Probability__c = o.Combined_Probability__c;
                s.Close_Date__c = o.CloseDate;
                s.Projected_Ship_Date__c = o.Projected_Ship_Date__c;
                s.Projected_On_Site_Delivery_Date__c = o.Projected_On_Site_Delivery_Date__c;
                // Set fields on Opportunity based on MPS
                o.MPS_Status__c = s.MPS_Status__c;
                o.MPS_BV__c = s.MPS_BV__c;
                o.MPS_Comment__c = s.MPS_Comment__c;
                o.MPS_Scheduled_Ship_Date__c = s.MPS_Scheduled_Ship_Date__c;
                o.MPS__c = s.id;
                oppsToUpdate.add(o);
            }
       } 
        // Update all opportunities in one call
        update oppsToUpdate;
    }
}

 

 

 

I have thought about creating checkboxes to be checked when the a trigger updates a record, and reset the field with a time-based workflow, but I only need to stagger the time a few seconds before the field is reset. Is there any way I can achieve the same thing within the triggers?

 

Thanks,

ckellie

Best Answer chosen by Admin (Salesforce Developers) 
MarkWaddleMarkWaddle

Hi ckellie,

 

I'm glad to see the trigger code is working for you. :) To avoid recursive trigger calls use the technique described in this developerforce recipe.

 

Mark

All Answers

MarkWaddleMarkWaddle

Hi ckellie,

 

I'm glad to see the trigger code is working for you. :) To avoid recursive trigger calls use the technique described in this developerforce recipe.

 

Mark

This was selected as the best answer
Rahul S.ax961Rahul S.ax961

Hi ckellie,

 

I suggest this would be easy with workflow's, instead of triggers.

The answer to your question is similar to below post:

http://boards.developerforce.com/t5/Apex-Code-Development/Trigger-is-fired-twice-due-to-the-workflow-rule-field-update/m-p/123469

 

Hope it helps,

ckellieckellie

Mark,

 

Thank you so much for your help. The page you sent me one recursive triggers did the trick and the the solved the challenge. Thank you very much.

 

ckellie

ckellieckellie

Rahul,

 

Thank you for the reference to the other workflow question. Unfortunately, workflows will not work as I am needing to update both records when one record is saved. Workflow rules only update the record you are working on after the record is saved, which will not meet our need.

 

Thank you for the suggestion,

 

ckellie

raju123raju123

hI ckellie,

 

I to have same problem.

 

ian application where the user will create a custom object (mps) record from the opportunity and a trigger will update certain fields on the mps from the opportunity.When there is an MPS record attached to the opportunity, the opportunity will update the mps, and when the mps is updated, the opportunity is updated. This has created an error that says "...cannot recursively update itself..." I am trying to find a way to prevent this. The problem is I cannot the find a way to break this recursion

please help me.I dont know where exactly i need to keep static variables

can any one put static varibles in follwing code and send me back .

Thanking u 


ckellie wrote:

I am working on an application where the user will create a custom object (mps) record from the opportunity and a trigger will update certain fields on the mps from the opportunity.When there is an MPS record attached to the opportunity, the opportunity will update the mps, and when the mps is updated, the opportunity is updated. This has created an error that says "...cannot recursively update itself..." I am trying to find a way to prevent this. The problem is I cannot the find a way to break this recursion.

 

I wannt both records to be updated when one record is updated. Below are my triggers:

 

 

trigger OppUpdateMPS on Opportunity (before update) {
       Map<Id, Id> mapOpportunitytoMPS = new Map<Id, Id>();

    for(Opportunity o : trigger.new){
        // Populate map of Opportunity.Id to MPS.Id
        if (o.MPS__c != null) {
            mapOpportunitytoMPS.put(o.Id, o.mps__c);
        }
    }

    if (!mapOpportunitytoMPS.isEmpty()) {
        // Query all relevant opportunities to a map with key of Opportunity.Id
        Map<Id, MPS__c> mps = new Map<Id,MPS__c>([select id, MPS_BV__c, MPS_Comment__c, 
                         MPS_Scheduled_Ship_Date__c, MPS_Status__c, Close_Date__c, LastModifiedDate,
                         Projected_Ship_Date__c, Projected_On_Site_Delivery_Date__c,
                         Forecast_Category__c, Combined_Probability__c, Recursive_Update__c
                         from MPS__c where id in:mapOpportunitytoMPS.values()]);

        List<MPS__c> mpsToUpdate = new List<MPS__c>();
        Id mpsId;
        MPS__c m;

        for (Opportunity s : trigger.new) {
            if (mapOpportunitytoMPS.containsKey(s.Id)) {
                // Get the MPS__c ID from the map
                mpsId = mapOpportunitytoMPS.get(s.Id);
                // Get the opportunity based on the opportunity ID
                m = mps.get(mpsId);
                // Set fields on MPS based on Opportunity
                m.Forecast_Category__c = s.ForecastCategoryName;
                m.Combined_Probability__c = s.Combined_Probability__c;
                m.Close_Date__c = s.CloseDate;
                m.Projected_Ship_Date__c = s.Projected_Ship_Date__c;
                m.Projected_On_Site_Delivery_Date__c = s.Projected_On_Site_Delivery_Date__c ;
                m.MPS_Scheduled_Ship_Date__c = s.MPS_Scheduled_Ship_Date__c;
                MPSToUpdate.add(m);
            }
        }

        // Update all MPS__c in one call
        update MPSToUpdate;
        
    }
}

 

trigger MPSUpdate on MPS__c (Before Insert, Before Update) {
    Map<Id, Id> mapMpsToOpportunity = new Map<Id, Id>();
     
    for(MPS__c mps : trigger.new){
        // Populate map of MPS.Id to Opportunity.Id
        if (mps.OpportunityID__c != null) {
            mapMpsToOpportunity.put(mps.Id, mps.OpportunityID__c);
        }
    }
    
    if (!mapMpsToOpportunity.isEmpty()) {
        // Query all relevant opportunities to a map with key of Opportunity.Id
        Map<Id, Opportunity> opps = new Map<Id, Opportunity>([select id, MPS_BV__c, MPS_Comment__c, 
                         MPS_Scheduled_Ship_Date__c, MPS_Status__c, CloseDate,
                         Projected_Ship_Date__c, Projected_On_Site_Delivery_Date__c,
                         ForecastCategoryName, Combined_Probability__c
                         from Opportunity where id in:mapMpsToOpportunity.values()]);

        List<Opportunity> oppsToUpdate = new List<Opportunity>();
        Id oppId;
        Opportunity o;
        for (MPS__c s : trigger.new) {
            if (mapMpsToOpportunity.containsKey(s.Id)) {
                // Get the opportunity ID from the map
                oppId = mapMpsToOpportunity.get(s.Id);
                // Get the opportunity based on the opportunity ID
                o = opps.get(oppId);
                // Set fields on MPS based on Opportunity
                s.Forecast_Category__c = o.ForecastCategoryName;
                s.Combined_Probability__c = o.Combined_Probability__c;
                s.Close_Date__c = o.CloseDate;
                s.Projected_Ship_Date__c = o.Projected_Ship_Date__c;
                s.Projected_On_Site_Delivery_Date__c = o.Projected_On_Site_Delivery_Date__c;
                // Set fields on Opportunity based on MPS
                o.MPS_Status__c = s.MPS_Status__c;
                o.MPS_BV__c = s.MPS_BV__c;
                o.MPS_Comment__c = s.MPS_Comment__c;
                o.MPS_Scheduled_Ship_Date__c = s.MPS_Scheduled_Ship_Date__c;
                o.MPS__c = s.id;
                oppsToUpdate.add(o);
            }
       } 
        // Update all opportunities in one call
        update oppsToUpdate;
    }
}

 

 

 

I have thought about creating checkboxes to be checked when the a trigger updates a record, and reset the field with a time-based workflow, but I only need to stagger the time a few seconds before the field is reset. Is there any way I can achieve the same thing within the triggers?

 

Thanks,

ckellie


 

ckellieckellie

Raju,

 

Since working on this code, I found a solution that worked better for me.

 

1. Make a Master-Detail relationship Opportunity-MPS format.

2. All of the Opportunity-related fields can now be formula fields.

3. Add a lookup field the on the Opportunity.

4. Create a VF page/extension for the record creation.

5. Create an After Insert trigger updating the MPS__c lookup field on the Opportunity.

6. Create Opportunity formula fields to pull the MPS__c information onto the Opportunity.

Ramesh SomalagariRamesh Somalagari
Hi All I have same problem.Can you please click this link http://salesforce.stackexchange.com/questions/43871/system-dmlexception-delete-failed-self-reference-from-trigger See the log I a have got same issue.