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
jmasl7xjmasl7x 

Trigger works but is it efficient?

I've created the following Apex Trigger and tested it in our sandbox environment. SFA_Order__c is a custom object we use to capture Orders and SFA_Delivery_Location__c is a non-mandatory field which is defined as lookup(Account).

Code:
trigger SFA_AU_setDeliveryAddress on SFA_Order__c (before update, before insert) {

    SFA_Order__c[] ords = Trigger.New;
    for (SFA_Order__c ord: ords) {
        String rt = ord.RecordTypeId;
        RecordType[] rts = [select Name from RecordType where id = :rt];
        if (rts.size() > 0 && rts[0].Name.startsWith('SFA AU')) {
        
            String acid;
            if (ord.SFA_Delivery_Location__c != null) acid = ord.SFA_Delivery_Location__c;
            else acid = ord.SFA_Account__c;
            
            Account[] ac = [Select BillingStreet,BillingPostalCode,BillingCity
                            from Account where Id = :acid];
            if (ac.size() > 0) {
                ord.SFA_Account_Street__c = ac[0].BillingStreet;
                ord.SFA_Account_ZIP_Code__c = ac[0].BillingPostalCode;
                ord.SFA_Account_City__c = ac[0].BillingCity;       
            } 
        }
    }
}

 My question regards the retrieval of the Record Type name in order to make the comparison
rts[0].Name.startsWith('SFA AU')

It seems to me inefficient that the trigger should be querying the RecordType object (table?) every time it is executed. But is there a better way to do this? I thought perhaps I could specify

ord.RecordType.Name

in my comparison, but this gives me a error at runtime:

System.NullPointerException

Any help appreciated.

Regards

John
ShamSham
During the execution of trigger only the object values are loaded hence you won't be able to use
ord.RecordType.Name
The issue with the trigger it will fail if data is loaded in bulk
from DataLoader
because Trigger permits a total of 20 SOQL queries.

you should modify your trigger

Set<ID> setID = new Set<ID>();
for (SFA_Order__c ord: ords) {
setID.add(ord.RecordTypeId);

Map<Id,RecordType> mp = new Map<Id,RecordType>([Select Id,Name from RecordType where ID IN :setID]);

for (SFA_Order__c ord: ords) {
string recordName = mp.get(ord.RecordTypeId).Name



jmasl7xjmasl7x
Sham,

thanks for the information.

Is there any way to predict how many records will be loaded in bulk per invocation of the trigger?

I assume if the trigger runs with 20 (or more) records in the Trigger.New array then it would still fail because I'd be running 20 queries to Account and 1 to RecordType (?)

Should I be building a Map of Accounts at the start of the process in a similar way that you showed me for RecordTypes?

Regards

John
sfdcfoxsfdcfox
Yes, you must minimize the queries that you use; using a query inside a for loop is a recipe for govenor errors. A trigger will load up to 200 records at once, so your code must be prepared to handle that many records. Using Maps, Sets, and Lists, you can easily create efficient queries to handle hundreds of records at once.