1

I have created a trigger that acts both before update and before insert but the insert side of my trigger works fine but when i try to update i get this error:

Apex trigger LineItemCreation caused an unexpected exception, contact your administrator: LineItemCreation: execution of BeforeUpdate caused by: System.DmlException: Delete failed. First exception on row 0 with id 00o9E000000KhACQA0; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 00k9E000002xUyx) is currently in trigger LineItemCreation, therefore it cannot recursively update itself: []: Trigger.LineItemCreation: line 90, column 1

The after update part of my trigger it referencing too is like so:

 if(trigger.isUpdate && trigger.isBefore){
    List<OpportunityLineItemSchedule> getSchedules = new List<OpportunityLineItemSchedule>();
    getSchedules = [SELECT Id, Revenue FROM OpportunityLineItemSchedule
                    WHERE OpportunityLineItemId =:OLI.Id];
        System.debug('Update actioned' + getSchedules);
        if(!getSchedules.isEmpty()){
            System.debug('Items Delete' + GetSchedules);
            delete getSchedules;
            System.debug('Gone' + GetSchedules);

        }
    }

My whole code is here, also any improvements you can offer me in general or best practice i would really appreciate as ive only just started learning apex.

trigger LineItemCreation on OpportunityLineItem (after insert,before update, after update) {
    for(OpportunityLineItem OLI :Trigger.new){
        if(trigger.isInsert  && trigger.isAfter){


        Product2 productsRef = new Product2();
        Opportunity oppRef = new Opportunity();

        System.Debug('Opportunity Line Quantity = ' + OLI.Quantity);  
            try{
        productsRef = [SELECT Id, Basis__c, Family FROM Product2 WHERE
                        Id =:OLI.Product2Id]; 

        System.Debug('product List created = ' + productsRef);
            }
            catch(Exception e){
                 System.debug('The following exception has occurred: ' + e.getMessage());
            }
        oppRef = [SELECT Id, Contract_Start_Date__c, 
                              Contract_End_Date__c FROM Opportunity
                              WHERE Id=:OLI.OpportunityId];

        System.Debug('Opportunity List created = ' + oppRef);
        System.Debug('Opportunity List created = ' + OLI.TotalPrice);
        System.Debug('Opportunity Line Quantity = ' + OLI.Quantity);  

        Integer daysDiff = oppRef.Contract_Start_Date__c.daysBetween(oppRef.Contract_End_Date__c);

        System.Debug('DaysDifference = ' + daysDiff);
        Decimal OliDayPrice = (OLI.TotalPrice / daysDiff);
        System.Debug('Dailys Schedule Record Price = ' + oliDayPrice);
        List<OpportunityLineItemSchedule> OLISlist = new List<OpportunityLineItemSchedule>();
        Decimal totalPaid = 0;
        for(Integer i=0; i < daysDiff; i++){
            System.Debug('for loop');

        if(productsRef.Basis__c =='Monthly' && productsRef.Family=='Licensing'){
                OpportunityLineItemSchedule OLISl = new OpportunityLineItemSchedule(
                OpportunityLineItemId=OLI.Id,
                Revenue=OliDayPrice,
                ScheduleDate=(oppRef.Contract_Start_Date__c + i), //issue with it adding on revenue to saleprice
                Type='Revenue');
                OLISlist.add(OLISl);
            System.Debug(OLISlist);
            System.Debug('Inc' + totalPaid);
        }   
        }
        System.debug('Total : ' + totalPaid);
            if(!OLISlist.isEmpty()){
            insert OLISlist;
            System.debug('List Inserted:' + OLISlist); 
            }
        }






if(trigger.isUpdate && trigger.isBefore){
    List<OpportunityLineItemSchedule> getSchedules = new List<OpportunityLineItemSchedule>();
    getSchedules = [SELECT Id, Revenue FROM OpportunityLineItemSchedule
                    WHERE OpportunityLineItemId =:OLI.Id];
        System.debug('Update actioned' + getSchedules);
        if(!getSchedules.isEmpty()){
            System.debug('Items Delete' + GetSchedules);
            delete getSchedules;
            System.debug('Gone' + GetSchedules);

        }
    }
}
}

1 Answer 1

3

First, you should not use queries or DML operations in a loop. Please read Best Practice: Bulkify Your Code for more details. Basically, for queries, you need to gather your inputs, query once, and use Maps afterwards. For DML operations, make a list, add all the items to the list, then perform the operation.

Second, you should use Checkpoints instead of spamming debug statements. You don't want those getting in to your production code, because it'll drastically reduce your code's performance (i.e. your users will notice it takes longer to save records, and will complain about slowness, and not want to adopt Salesforce).

Third, you don't need to check before you insert/update/delete an empty list; this is a vestige left over from when governor limits were consumed by empty lists, which is no longer true. Now, such checks just waste CPU time and clutter up code.

Fourth, as to the actual error, I suspect that since the line item's schedule is changing, it causes a recursive trigger call back to the line item. You should instead use if(Trigger.isUpdate && Trigger.isAfter) instead of Trigger.isBefore, which should limit the recursion, since the database will be in its post-updated state at that point.

1
  • Wow super helpful, that's for being so thorough, I'll look into checkpoints as you're most definitely right, thanks again
    – Nebbyyy
    Nov 25, 2016 at 18:19

You must log in to answer this question.

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