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
Rob Nelson 8Rob Nelson 8 

Calling .put on Map of Custom Settings throw 'Collection is read-only' error.

trigger AssignByLeadSource on Lead (before insert) {
    // Use row locks to prevent race conditions
    {
        LeadSourceCounters__c[] temp = [SELECT Id FROM LeadSourceCounters__c FOR UPDATE];
        //LeadSourceCounters is a custom setting
    }
    
    Map<String, LeadSourceCounters__c> counters = LeadSourceCounters__c.getAll();
    //counters is a new map that pulls in all the counts from the custom setting.
    
    System.debug('LeadSourceCounters__c.getAll() = ' + LeadSourceCounters__c.getAll());
    System.debug(counters);
    
    for(Lead record: Trigger.new) {
        if(record.LeadSource==null) {
            //if LeadSource is null, we can't round robin it specially, so continue ends for loop.
            continue;
        }
        
        if(!counters.containsKey(record.LeadSource)) {
        //if LeadSource doesn't exist, adds it and sets value to zero.    
        
            LeadSourceCounters__c happydog = new LeadSourceCounters__c(
                Name=record.LeadSource, 
                Value__c=0
            );
                   
            counters.put(record.LeadSource, happydog);
        }
        
        counters.get(record.LeadSource).Value__c+=1;
        //add 1 to Value__c counter for that lead source
        record.AssignmentId__c = counters.get(record.LeadSource).Value__c;
    }
    upsert counters.values();
    //saves the updated counter for that lead source
}

Everything works great except the .put command. 
counters.put(record.LeadSource, happydog);

On that line it throws the error:

AssignByLeadSource: execution of BeforeInsert caused by: System.FinalException: Collection is read-only: External entry point

This might be a rookie question but how do I add an item to the map? All the examples I have seen use .put
 
GauravTrivediGauravTrivedi
Hi Nelson,

Try the following code it will work for you :
 
trigger AssignByLeadSource on Lead (before insert) {
    // Use row locks to prevent race conditions
    {
        LeadSourceCounters__c[] temp = [SELECT Id FROM LeadSourceCounters__c FOR UPDATE];
        //LeadSourceCounters is a custom setting
    }
    
    Map<String, LeadSourceCounters__c> counters = LeadSourceCounters__c.getAll();
    //counters is a new map that pulls in all the counts from the custom setting.
	
	Map<String, LeadSourceCounters__c> counterMap = new Map<String, LeadSourceCounters__c>();
    
    System.debug('LeadSourceCounters__c.getAll() = ' + LeadSourceCounters__c.getAll());
    System.debug(counters);
    
    for(Lead record: Trigger.new) {
        if(record.LeadSource==null) {
            //if LeadSource is null, we can't round robin it specially, so continue ends for loop.
            continue;
        }
        
        if(!counters.containsKey(record.LeadSource)) {
        //if LeadSource doesn't exist, adds it and sets value to zero.    
        
            LeadSourceCounters__c happydog = new LeadSourceCounters__c(
                Name=record.LeadSource, 
                Value__c=0
            );
                   
            counterMap.put(record.LeadSource, happydog);
        }
        
        counterMap.get(record.LeadSource).Value__c+=1;
        //add 1 to Value__c counter for that lead source
        record.AssignmentId__c = counterMap.get(record.LeadSource).Value__c;
    }
    upsert counterMap.values();
    //saves the updated counter for that lead source
}

Let me know if it doesnt work.
AshlekhAshlekh
Hi Rob,

Bascially you are getting error in below line

counters.put(record.LeadSource, happydog);

Because you are fatching data directly in Counter Map from DB.

Map<String, LeadSourceCounters__c> counters = LeadSourceCounters__c.getAll(); So system has locked the lenght of this map so we cann't add more item in this.

You can use above code which is provided by Gaurav.

-Thanks
Ashlekh Gera
 
Rob Nelson 8Rob Nelson 8
Leaving everything else the same, just adding .clone(); to the line fixed it. Apparently the map returned from a query is immutable, so by cloning it, we get one we can add it. 
 
Map<String, LeadSourceCounters__c> counters = LeadSourceCounters__c.getAll().clone();

See more answers here - http://salesforce.stackexchange.com/questions/99727/calling-put-on-map-of-custom-settings-cause-collection-is-read-only-apex-erro/99841#99841