1

I am trying to move my trigger into a class, and then call the class from the trigger. However, I'm getting an error when I try to do an insert, update or delete on my VOActivity object. The error says that the list that I'm trying to update, activitiesToUpdate, is read only. See below:

VOActivityTrigger: execution of AfterInsert caused by: System.FinalException: Collection is read-only: Class.VOActivitySequence.newSequence: line 70, column 1

This error didn't happen when I had my logic in the trigger, but after I moved it into the class I keep getting the error. Does anyone know what this error means, and how I could go about fixing it? Thank you in advance for any suggestions and help!

TRIGGER

trigger VOActivityTrigger on VOActivity__c (after insert, after update, after undelete, after delete, before insert, before update, before delete) {

    if(trigger.isInsert && trigger.isAfter){
        VOActivitySequence.newSequence(trigger.new);
        }

    if(trigger.isUpdate && trigger.isAfter){
        VOActivitySequence.newSequence(trigger.old);
        }

    if(trigger.isDelete && trigger.isAfter){
        VOActivitySequence.newSequence(trigger.old);
        }
}

CLASS

public class VOActivitySequence{
    public static void newSequence(List<VOActivity__c> activitiesToUpdate){
        Set<Id> parentIds = new Set<Id>();
        List<Clinical_Study__c> parentStudiesById = new List<Clinical_Study__c>();
    Map<String, List<VOActivity__c>> nameToActivity = new Map<String, List<VOActivity__c>>();

    if(!activitySequence.hasAlreadyCreatedSequence())
    { //class to stop recursive trigger

            for(VOActivity__c vo: activitiesToUpdate)
            {
                parentIds.add(vo.Clinical_Study__c);
            }

            if(parentIds.size() > 0)
            {    
                parentStudiesById = [SELECT
                    Id, (SELECT
                        Id, Activity_Sequence__c, Scheduled_Date__c, Activity__c
                        FROM Vendor_Oversight_Activities__r
                        ORDER BY Scheduled_Date__c)
                    FROM Clinical_Study__c
                    WHERE Id IN :parentIds
                ];

                for(VOActivity__c a: [
                    SELECT Id, Clinical_Study__c, Activity__c, Apex_Updated__c
                    FROM VOActivity__c
                    WHERE Clinical_Study__c IN :parentIds])
                {
                    if(!nameToActivity.containsKey(a.Activity__c))
                    {
                        nameToActivity.put(a.Activity__c, new List<VOActivity__c>());
                    }
                    nameToActivity.get(a.Activity__c).add(a);
                }

                if(parentStudiesById.size() > 0)
                {
                    for(Clinical_Study__c cs: parentStudiesById)
                    {
                        Map<String, Integer> activityTypetoNumRecords  = new Map<String, Integer>();
                        for(VOActivity__c ac: cs.Vendor_Oversight_Activities__r)
                        {
                            if(nameToActivity.containsKey(ac.Activity__c))
                            {
                                if(!activityTypeToNumRecords.containsKey(ac.Activity__c))
                                {
                                    activityTypeToNumRecords.put(ac.Activity__c, 0);
                                }

                                Integer num = activityTypeToNumRecords.remove(ac.Activity__c) + 1;
                                activityTypeToNumRecords.put(ac.Activity__c, num);
                                ac.Activity_Sequence__c = '(' + num + ' of ' + activityNameToActivityRecordMap.get(ac.Activity__c).size() + ')';
                                ac.Apex_Updated__c = System.currentTimeMillis();
                                activitiesToUpdate.add(ac);
                            }
                            else if(ac.Activity__c == null){
                                ac.Activity_Sequence__c = null;
                                activitiesToUpdate.add(ac);
                            }
                        }
                    }

                    activitySequence.setAlreadyCreatedSequence();

                    update activitiesToUpdate;
                }
            }
        }
    }
}
  • What are you trying to achieve with this line ? activityNameToActivityRecordMap.get(a.Activity__c).add(a); } – Mihai Neagoe Jan 31 '15 at 22:39
  • Hi @MihaiNeagoe . This trigger is for sequencing child activities (1 of 3), (2 of 3), etc. There are different types of activities designated by the Activity__c field (i.e. Type 1, Type 2, etc.) The sequencing must be unique for each type. activityNameToActivityRecordMap.get(a.Activity__c).add(a); gets the Activity type and adds it to the keys in the map – rwegner7 Jan 31 '15 at 22:48
  • Holy nested logic, Batman! You are trying to do way too much in your code at once. The fact that at one point your code reads } } } activitySequence.setAlreadyCreatedSequence(); update activitiesToUpdate; } } } } } should be a serious red flag. – Adrian Larson Jan 31 '15 at 22:58
4

I am guessing these lines are giving you the error:

activitiesToUpdate.add(ac);

You cannot add records to the trigger.new or trigger.old lists.

You can only modify the values of the records in the list for before triggers. But since they are after triggers you cannot modify them at this point either

  • Hi @Eric . I modified the trigger to call the class on Before Insert and still get the same error. Is there a way that I can modify the class to make it work? Or does "after insert, after update, after delete" logic for records only work in triggers, and not in classes?? – rwegner7 Jan 31 '15 at 22:54
  • @rwegner You cannot modify the list only the items in it.....So if you are ding a before trigger, get the item from the list and modify the values. No need to put it back in the list as the items are modified by reference.... – Eric Jan 31 '15 at 22:56
  • thanks for your suggestion. This class needs to perform after functions, I double checked, before doesn't work. – rwegner7 Jan 31 '15 at 23:21
  • @rwegner7 - The only way you can modify records IN the trigger in an after is Async. Use future. Either way you still cannot add or remove records from the list of records in the trigger. – Eric Jan 31 '15 at 23:52
  • it must just be an issue with the way I'm architecting my class and trigger. going through these guides to see if there's a way to make it work... embracingthecloud.com/2010/07/08/… ; gokubi.com/archives/… – rwegner7 Feb 1 '15 at 0:21
0

ANSWER:

The issue was that I was trying to add records to the list "activitiesToUpdate", which was the list I passed into my method. As Eric stated, I cannot add records to trigger.new or trigger.old for an after trigger. These lists can only be read-only.

The solution was to create another list in my code for adding/updating/deleting records. The new list isn't restricted by the trigger.new and trigger.old parameters. See below for the major aspects of the answer.

public static void newSequence(List<VOActivity__c> activitiesToUpdate){//the list is passed in here with the parameters trigger.new and trigger.old. Because it is an after trigger it is a read only list

List<VOActivity__c> activitiesToUpateFinal = new List<VOActivity__c>();//my new list to add records to
...
for(VOActivity__c vo: activitiesToUpdate)//the passed in list is still used here to get parent object ids
        {
            parentIds.add(vo.Clinical_Study__c);
        }
...
activitiesToUpdateFinal.add(ac);//add records to the new list
...
update activitiesToUpdateFinal;//update the new list
  • Well glad you figured it out with our help you even got to vote your solution based on the help received here as the answer......Chicken or egg...... – Eric Feb 3 '15 at 4:23
  • @Eric I appreciate your answer, but my reason for posting on here was to solve the problem, not just understand the error. In my original post I asked "Does anyone know what this error means, and how I could go about fixing it?". Thank you for answering the first part of my question, I gave you an up arrow for it. – rwegner7 Feb 3 '15 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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