+ Start a Discussion
JNicJNic 

trigger problems: record is read only

Hi all,

 

I'm attempting to call a class from a trigger that crabs the name of an object based on an Id:

 

Trigger:

 

trigger woJctUpdate on woJct__c (before insert, before update) {
	
	List<woJct__c> newj = (Trigger.old != null) ? Trigger.old : Trigger.new;
	workOrderUtils.theWoJct(newj);
}

 Class:

 

public with sharing class workOrderUtils {

public static List <woJct__c> woJcts = new List<woJct__c>();

public static string getNameById(string id) {

Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
Map<String,String> keyPrefixMap = new Map<String,String>{};
Set<String> keyPrefixSet = gd.keySet();
for(String sObj : keyPrefixSet){
Schema.DescribeSObjectResult r = gd.get(sObj).getDescribe();
String tempName = r.getName();
String tempPrefix = r.getKeyPrefix();
keyPrefixMap.put(tempPrefix,tempName);
}

string tPrefix = id.subString(0,3);
string objectName = keyPrefixMap.get(tPrefix);
System.debug('objectName:::::' + objectName);

sObject retObject = Database.query(
' SELECT id, name' +
' FROM ' + objectName +
' WHERE id=\'' + id + '\'');


return (string)retObject.get('name');
}

public static void theWoJct(List<woJct__c> objs) {
for (woJct__c woJct : objs) {
if (woJct.relatedToId__c != null) {
woJct.relatedToName__c = getNameById(woJct.relatedToId__c); /<----- This is 33, 8
woJcts.add(woJct);
}
}
if (woJcts.size() > 0) {
update woJcts;
}
}
}

 But when a save a woJct__c it throws me an error:

 

Error:Apex trigger woJctUpdate caused an unexpected exception, contact your administrator: woJctUpdate: execution of BeforeUpdate caused by: System.Exception: Record is read-only: Class.workOrderUtils.theWoJct: line 33, column 8

 

I've tried all kinds of stuff... I can't figure it out... Any help would be great!

 

Thanks.

JNH

 

 

Best Answer chosen by Admin (Salesforce Developers) 
David81David81

Now I may be wrong here, because I'm a bit new to this myself, but when you pass those records from the trigger to the class, you are passing them by reference, so any modifications you make, you make to the record itself. My guess is that the class can't get access to it because the trigger still has it locked. This is just a guess though.

 

With such simple logic in that method, I'd be tempted to just move it into your trigger and call your getNamebyId method directly.

All Answers

David81David81

You've got that update call in your method but the trigger calling it is a before trigger, so the records are still held by the trigger itself, no need for an update call.

JNicJNic

Thanks David, I commented out the update call in the class, but the error still remains...

 

For some reason it seems to say that this

 

woJct.relatedToName__c = getNameById(woJct.relatedToId__c);

 

 

cannot be called because the record is read only... but I'm just adding it to a list, not updating the record yet, correct?

 

Thats the reason I was calling the update in the class... so I added it to the list, then updated the list once it was all done..

David81David81

Now I may be wrong here, because I'm a bit new to this myself, but when you pass those records from the trigger to the class, you are passing them by reference, so any modifications you make, you make to the record itself. My guess is that the class can't get access to it because the trigger still has it locked. This is just a guess though.

 

With such simple logic in that method, I'd be tempted to just move it into your trigger and call your getNamebyId method directly.

This was selected as the best answer
JNicJNic

Well... you're right david...

I wanted to make it a little more modular / scaleable, but it seems not to want to work with me. I changed it to this:

 

 

trigger woJctUpdate on woJct__c (before insert, before update) {
	
	public string relatedToObject {get;set;}
    
    public string getNameById(string id) {

        Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe(); 
        Map<String,String> keyPrefixMap = new Map<String,String>{};
        Set<String> keyPrefixSet = gd.keySet();
        for(String sObj : keyPrefixSet){
           Schema.DescribeSObjectResult r =  gd.get(sObj).getDescribe();
           String tempName = r.getName();
           String tempPrefix = r.getKeyPrefix();
           keyPrefixMap.put(tempPrefix,tempName);
        }

        string tPrefix = id.subString(0,3);
        string objectName = keyPrefixMap.get(tPrefix);
        System.debug('objectName:::::' + objectName);
        
        relatedToObject = string.valueOf(objectName);
        
        sObject retObject = Database.query(
                ' SELECT id, name' +
                ' FROM ' + objectName + 
                ' WHERE id=\'' + id + '\'');

		
        return (string)retObject.get('name');
    }
	
	for (woJct__c woj : trigger.new){
    	if (woj.relatedToId__c != null) {
    		woj.relatedToName__c = getNameById(woj.relatedToId__c);
    		woj.relatedToObject__c = relatedToObject;
    	}
    }
}

 BTW.... I kinda hacked how I get the object name... Is there a nicer way to do it? heh...

 

David81David81

Actually I was thinking to leave your class mostly intact and just update your trigger to:

 

 

trigger woJctUpdate on woJct__c (before insert, before update) {
	
for(woJct__c w : trigger.new){

if (w.relatedToId__c != null) {
w.relatedToName__c = workOrderUtils.getNameById(w.relatedToId__c);   

}

}

 

As far as getting the name goes, you can use the getSObjectType method on an sObject to return the token for that object. Probably a way to work that into your code, I'll think on it.