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
Usha Charles 3Usha Charles 3 

Autoupdate field on Account object

Hello,

I have the below code to update the country field if the state field is filled. I was able to save the trigger but I'm getting the following error while I try to save a record with the state field. I have System Administrator profile & ave Read/Write Access on Account object..

Please let me know where I have gone wrong, I'm an administrator trying to learn Apex.

1 trigger SU on Account (After update, After insert) {
2     for(Account acct : Trigger.new){
3         if (acct.Billing_state__c == 'Karnataka'){
4             acct.Country__c = 'India';
5             Update acct;
6         }
7     }
8
9 }
10 /** Unsucessful - get this error - Apex trigger SU caused an unexpected exception, contact your administrator: 
11 *SU: execution of AfterInsert caused by: System.FinalException: Record is read-only: Trigger.SU: line 4, column 1
12 **/

 Apex trigger SU caused an unexpected exception, contact your administrator: SU: execution of AfterInsert caused by: System.FinalException: Record is read-only: Trigger.SU: line 4, column 1


Thanks,
Usha


 
Best Answer chosen by Usha Charles 3
pigginsbpigginsb
Hi, Usha.

Because your trigger fires After Insert, After Update, the records in the trigger.new list are read-only. They have already been saved to the database.

In a Before Insert, Before Update trigger, the records are still on their way into the database, and you'll be able to write to the fields inside trigger.new. Another advantage of switching to a Before trigger here is that since the records you want to write to are on their way into the database, you will not need to use an Update statement. You can just write to the record and it continues to the database with it's new value.

I think you would see the Country value you are expecting if you change your trigger from After to Before.

I also think you could consider using a formula field to provide the Country value. This would give you click and configure access to add more states and countries without having to update any Apex code. I think even a workflow rule would be able to update the Country based on State name.

But if you're goal here is to learn Apex anyway, then you could include Country values in a map where the State name is the key.
// by using a map to provide Country names based on State names...
Map<String, String> countryMap = new Map<String, String> {
    'Karnataka' => 'India',
    'Kerala' => 'India',
    'Kansas' => 'USA'
}

// you will not need to specifically check for each state by it's name...
for (Account each : trigger.new) {
    // if the country map contains the state name as a key...
    if (countryMap.containsKey(each.Billing_State__c)) {
        // you can assign the value from the map to the account's country field
        each.Country__c = countryMap.get(each.Billing_State__c);
    }
}
I look forward to hearing how it goes!
 

All Answers

pigginsbpigginsb
Hi, Usha.

Because your trigger fires After Insert, After Update, the records in the trigger.new list are read-only. They have already been saved to the database.

In a Before Insert, Before Update trigger, the records are still on their way into the database, and you'll be able to write to the fields inside trigger.new. Another advantage of switching to a Before trigger here is that since the records you want to write to are on their way into the database, you will not need to use an Update statement. You can just write to the record and it continues to the database with it's new value.

I think you would see the Country value you are expecting if you change your trigger from After to Before.

I also think you could consider using a formula field to provide the Country value. This would give you click and configure access to add more states and countries without having to update any Apex code. I think even a workflow rule would be able to update the Country based on State name.

But if you're goal here is to learn Apex anyway, then you could include Country values in a map where the State name is the key.
// by using a map to provide Country names based on State names...
Map<String, String> countryMap = new Map<String, String> {
    'Karnataka' => 'India',
    'Kerala' => 'India',
    'Kansas' => 'USA'
}

// you will not need to specifically check for each state by it's name...
for (Account each : trigger.new) {
    // if the country map contains the state name as a key...
    if (countryMap.containsKey(each.Billing_State__c)) {
        // you can assign the value from the map to the account's country field
        each.Country__c = countryMap.get(each.Billing_State__c);
    }
}
I look forward to hearing how it goes!
 
This was selected as the best answer
pigginsbpigginsb
I would like to add also, that if you use an Update statement to update Accounts in a trigger that fires when an Account gets updated, you will cause the trigger to repeatedly fire upon itself. It this must be a trigger, it is best to use a Before trigger and remove the Update statement.
Usha Charles 3Usha Charles 3
Hi,

Thanks again ! I learnt how Maps & List can be used !

I'm actually going through Apex workbooks / trailhead & trying to code myself so have taken dummy scenerios to try, I would offcourse look for Declarative methods first !

 thank you very much for taking time in answering my questions !