Salesforce Apex error: SELF_REFERENCE_FROM_TRIGGER

apex-codesalesforce

Error: Invalid Data. 
Review all error messages below to correct your data.
Apex trigger triggerOpportunityCloseInstallDateChange caused an unexpected exception, contact your administrator: triggerOpportunityCloseInstallDateChange: execution of BeforeUpdate caused by: System.DmlException: Delete failed. First exception on row 0 with id 00o30000003ySNhAAM; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 0063000000i23T9) is currently in trigger triggerOpportunityCloseInstallDateChange, therefore it cannot recursively update itself: []: Class.OpportunitySchedule.BuildScheduleAndUpdateDates: line 17, column 5

I'm getting the above error when I try to excute the code below.

I have a trigger on the "before" of an opportunity. It then calls the below class with trigger.new.

public with sharing class OpportunitySchedule {

    public static void BuildScheduleAndUpdateDates(List<Opportunity> OpportunityList) {

        for (Integer i = 0; i < OpportunityList.size(); i++)
        {
            Opportunity opp_new = OpportunityList[i];

            List<OpportunityLineItem> lineItems = [Select o.Id, (Select OpportunityLineItemId From OpportunityLineItemSchedules), o.System_Add_on__c, o.ServiceDate, o.Schedule_Length__c , o.Monthly_Quantity__c, o.Monthly_Amount__c
                                                From OpportunityLineItem o
                                                where o.Opportunity.Id =  :opp_new.Id];

            for (OpportunityLineItem item : lineItems)
            {
                item.ServiceDate = opp_new.CloseDate;
                update item;
                delete item.OpportunityLineItemSchedules;       
            }                                   
        }
    }
}

I'm trying to delete all of the Opportunity Line Item Schedules when someone edits an opportunity. The weird thing is, I can remove the delete item.OpportunityLineItemSchedules line and the code runs, it will update the item. I don't understand why deleting a childs children (Opportunity -> OpportunityLineItem -> OpportunityLineItemSchedule) would cause a recursive loop.

I've tried implimenting the below code in this link with no luck:
http://boards.developerforce.com/t5/Apex-Code-Development/Trigger-is-fired-twice-due-to-the-workflow

I've also commented out all other triggers to make sure one of them aren't causing it.

Does anyone know what I'm doing wrong?

Best Answer

A few things I noticed. First, never put DML inside a loop and especially when inside of a trigger. Reading up on Bulkified triggers here would help: http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_triggers.htm

In your code you're almost there. Instead of doing your update in the loop, simply update your entire list after the loop:

for (OpportunityLineItem item : lineItems)
{
   item.ServiceDate = opp_new.CloseDate;
   //update item;
   //delete item.OpportunityLineItemSchedules;       
}

update lineItems;

Then you would make a new list of just OpportunityLineItemSchedules that had ParentId == OpportunityLineItem.Id. Then you would delete that entire list in one call:

delete saidList;

As for the recursion, in a master-detail relationship Force.com will handle the deletion of children automatically. Not so in a lookup, where you need to delete these by hand. Though I'm uncertain about OpportunityLineItemSchedules specifically, I'd try either starting things with using an AFTER trigger, or use a helper class that your trigger thread keeps in memory to ensure that once inside of your trigger handler class, that it doesn't enter it again.

Unfortunately the above is all I had a moment to share! Good luck and welcome to Force.com programming. Hope it grows on you.

Related Topic