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
Anthony HuerterAnthony Huerter 

Error When trying to execute a Opportuntiy Trigger

I am trying to build my frist trigger and I am stuck on somthing I am sure is very simple.  I am trying to update the Territory field on the opportutniy when a text field is a certain value on the opportutniy.  This is the field I am trying to update.

User-added image

here is my code

trigger OpportuntiyTerritoryID on Opportunity (After insert, after update) {
    for(opportunity opp : trigger.new)
        if (opp.Transaction_Territory__c == 'South East')
    {Opp.Territory2Id = '0MI180000004DOG';}
        }
       

And I am getting this error when I go to update that 'Transaction Territory' Text field.

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

Any help is greatly appreciated.
Best Answer chosen by Anthony Huerter
Amit Chaudhary 8Amit Chaudhary 8
Hi Anthony Huerter,

Issue is coming because you are using After Update and After Insert trigger to update same record. Please try below before event
Issue in your code
1) After event please try before even
2) Hard coded ID for Territory2Id .

Please try below code
trigger OpportuntiyTerritoryID on Opportunity (before insert, before update) 
{
	//Id territortyId = [select id from Territory where name ='dfdfd'];

    for(opportunity opp : trigger.new)
	{
        if (opp.Transaction_Territory__c == 'South East')
		{
			Opp.Territory2Id = '0MI180000004DOG'; // Try to get this ID from Query for using for loop(like territortyId)
		}
	}
}

If you want to learn about Trigger then please try below trailhead module
1) https://developer.salesforce.com/trailhead/module/apex_triggers

Please check below post Trigger best pratice
1) http://amitsalesforce.blogspot.in/2015/06/trigger-best-practices-sample-trigger.html

1) One Trigger Per Object
A single Apex Trigger is all you need for one particular object. If you develop multiple Triggers for a single object, you have no way of controlling the order of execution if those Triggers can run in the same contexts

2) Logic-less Triggers
If you write methods in your Triggers, those can’t be exposed for test purposes. You also can’t expose logic to be re-used anywhere else in your org.

3) Context-Specific Handler Methods
Create context-specific handler methods in Trigger handlers

4) Bulkify your Code
Bulkifying Apex code refers to the concept of making sure the code properly handles more than one record at a time.

5) Avoid SOQL Queries or DML statements inside FOR Loops
An individual Apex request gets a maximum of 100 SOQL queries before exceeding that governor limit. So if this trigger is invoked by a batch of more than 100 Account records, the governor limit will throw a runtime exception

6) Using Collections, Streamlining Queries, and Efficient For Loops
It is important to use Apex Collections to efficiently query data and store the data in memory. A combination of using collections and streamlining SOQL queries can substantially help writing efficient Apex code and avoid governor limits

7) Querying Large Data Sets
The total number of records that can be returned by SOQL queries in a request is 50,000. If returning a large set of queries causes you to exceed your heap limit, then a SOQL query for loop must be used instead. It can process multiple batches of records through the use of internal calls to query and queryMore

8) Use @future Appropriately
It is critical to write your Apex code to efficiently handle bulk or many records at a time. This is also true for asynchronous Apex methods (those annotated with the @future keyword). The differences between synchronous and asynchronous Apex can be found

9) Avoid Hardcoding IDs
When deploying Apex code between sandbox and production environments, or installing Force.com AppExchange packages, it is essential to avoid hardcoding IDs in the Apex code. By doing so, if the record IDs change between environments, the logic can dynamically identify the proper data to operate against and not fail

Let us know if this will help you

Thanks
Amit Chaudhary

All Answers

Amit Chaudhary 8Amit Chaudhary 8
Hi Anthony Huerter,

Issue is coming because you are using After Update and After Insert trigger to update same record. Please try below before event
Issue in your code
1) After event please try before even
2) Hard coded ID for Territory2Id .

Please try below code
trigger OpportuntiyTerritoryID on Opportunity (before insert, before update) 
{
	//Id territortyId = [select id from Territory where name ='dfdfd'];

    for(opportunity opp : trigger.new)
	{
        if (opp.Transaction_Territory__c == 'South East')
		{
			Opp.Territory2Id = '0MI180000004DOG'; // Try to get this ID from Query for using for loop(like territortyId)
		}
	}
}

If you want to learn about Trigger then please try below trailhead module
1) https://developer.salesforce.com/trailhead/module/apex_triggers

Please check below post Trigger best pratice
1) http://amitsalesforce.blogspot.in/2015/06/trigger-best-practices-sample-trigger.html

1) One Trigger Per Object
A single Apex Trigger is all you need for one particular object. If you develop multiple Triggers for a single object, you have no way of controlling the order of execution if those Triggers can run in the same contexts

2) Logic-less Triggers
If you write methods in your Triggers, those can’t be exposed for test purposes. You also can’t expose logic to be re-used anywhere else in your org.

3) Context-Specific Handler Methods
Create context-specific handler methods in Trigger handlers

4) Bulkify your Code
Bulkifying Apex code refers to the concept of making sure the code properly handles more than one record at a time.

5) Avoid SOQL Queries or DML statements inside FOR Loops
An individual Apex request gets a maximum of 100 SOQL queries before exceeding that governor limit. So if this trigger is invoked by a batch of more than 100 Account records, the governor limit will throw a runtime exception

6) Using Collections, Streamlining Queries, and Efficient For Loops
It is important to use Apex Collections to efficiently query data and store the data in memory. A combination of using collections and streamlining SOQL queries can substantially help writing efficient Apex code and avoid governor limits

7) Querying Large Data Sets
The total number of records that can be returned by SOQL queries in a request is 50,000. If returning a large set of queries causes you to exceed your heap limit, then a SOQL query for loop must be used instead. It can process multiple batches of records through the use of internal calls to query and queryMore

8) Use @future Appropriately
It is critical to write your Apex code to efficiently handle bulk or many records at a time. This is also true for asynchronous Apex methods (those annotated with the @future keyword). The differences between synchronous and asynchronous Apex can be found

9) Avoid Hardcoding IDs
When deploying Apex code between sandbox and production environments, or installing Force.com AppExchange packages, it is essential to avoid hardcoding IDs in the Apex code. By doing so, if the record IDs change between environments, the logic can dynamically identify the proper data to operate against and not fail

Let us know if this will help you

Thanks
Amit Chaudhary
This was selected as the best answer
Anthony HuerterAnthony Huerter
This was very helpful thank you Amit Chaudhary!

I  exanded this to be an else if statement as well to look at all the varinces that can be in the territory transaction field.  I am trying to create a test class for this so I can migrate to our production but I am not reachingthe 75% cover coverage. 

Test Class
@isTest
public class OpportuntiyTerritoryID     
{ static testMethod void OpportuntiyTerritoryID () 
   { //Create and insert opp  
     Opportunity opp = new Opportunity(Name='TEST opp', StageName='stage', Probability = 10, CloseDate=system.today());     
       insert opp;
       opp.Type ='New Sale';
       opp.Transaction_Territory__c = 'Great Lakes';
       insert opp;
  } 
  }

I am getting this error when I execute the test on the test class.  
System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, OpportuntiyTerritoryID: execution of BeforeInsert caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.OpportuntiyTerritoryID: line 38, column 1: []

and I am only at 40% on the apex trigger for coverage, any ideas on how to get to 75%?