Apex Trigger Scenarios – Part 1
Some Important Questions
Write a trigger to throw error when user deactivates the account record and if that account has atleast one opportunity with the stage not equal to closed won or closed lost.
trigger PreventAccountDeactivation on Account(before update) { // Loop through the list of accounts being updated for (Account acc: Trigger.new) { // Check if the account's IsActive field is being set to false (i.e. deactivated) if (acc.IsActive == false && Trigger.oldMap.get(acc.Id).IsActive == true) { // Query for opportunities related to this account where the stage is not "Closed Won" or "Closed Lost" List < Opportunity > opps = [ SELECT Id FROM Opportunity WHERE AccountId =: acc.Id AND StageName NOT IN('Closed Won', 'Closed Lost') ]; // If there are any such opportunities, throw an error if (!opps.isEmpty()) { acc.addError('Cannot deactivate this account because it has opportunities with a stage other than "Closed Won" or "Closed Lost".'); } } } }
Employee record's Status cannot be changed to "Terminated" if there is/are no Employee Review records added to it
trigger PreventTerminatedStatus on Employee__c (before update) { // Loop through the list of employees being updated for (Employee__c emp : Trigger.new) { // Check if the employee's Status field is being set to "Terminated" if (emp.Status__c == 'Terminated' && Trigger.oldMap.get(emp.Id).Status__c != 'Terminated') { // Query for Employee Review records related to this employee List<Employee_Review__c> reviews = [ SELECT Id FROM Employee_Review__c WHERE Employee__c = :emp.Id ]; // If there are no Employee Review records, throw an error if (reviews.isEmpty()) { emp.addError('Cannot set status to "Terminated" because there are no Employee Review records added to this employee.'); } } } }
Don't forget to check out: What are Apex Triggers? | All You Need to Know
There will be three objects User, Contact, and Account. and these objects have one custom field name is isActive. So, if I will uncheck the IsActive Checkbox from the Account then also uncheck the isActive checkbox of the related user of that account and all the contact associate with the account
trigger DeactivateRelatedRecords on Account (before update) { // Loop through the list of accounts being updated for (Account acc : Trigger.new) { // Check if the account's IsActive field is being set to false (i.e. deactivated) if (acc.IsActive == false && Trigger.oldMap.get(acc.Id).IsActive == true) { // Query for related users and contacts List<User> users = [ SELECT Id, IsActive FROM User WHERE AccountId = :acc.Id ]; List<Contact> contacts = [ SELECT Id, IsActive FROM Contact WHERE AccountId = :acc.Id ]; // Set the IsActive field to false for all related users and contacts for (User user : users) { user.IsActive = false; } for (Contact contact : contacts) { contact.IsActive = false; } // Update the related users and contacts update users; update contacts; } } }
What is the Difference Between Context variables and Static variables in triggers?
Context Variables:
- Context variables are variables that provide information about the context in which a trigger is executed.
- They are system-provided variables and cannot be explicitly defined or modified by the developer.
- Context variables are available only within the trigger execution context and are not accessible outside of it.
- Examples of context variables include Trigger.new, Trigger.old, Trigger.newMap, Trigger.oldMap, and Trigger.isBefore.
- These variables provide access to the records being processed by the trigger and allow developers to perform operations based on the trigger context.
Static Variables:
- Static variables, on the other hand, are variables that are explicitly defined and shared among all instances of a class.
- They are defined using the "static" keyword and are associated with the class itself, rather than with specific instances of the class.
- Static variables retain their values across multiple trigger invocations and can be accessed and modified by any method or trigger within the class.
- Unlike context variables, static variables are not tied to the trigger execution context and can be used outside of the trigger.
- Static variables are often used to store values that need to be shared across multiple trigger events or to maintain state information.
What are the Different types of Context variables in triggers?
Trigger Context Variables are:
isExecuting | Returns true if the current context for the Apex code is a trigger, not a Visualforce page, a Web service, or an executeanonymous() API call. |
isInsert | Returns true if this trigger was fired due to an insert operation, from the Salesforce user interface, Apex, or the API. |
isUpdate | Returns true if this trigger was fired due to an update operation, from the Salesforce user interface, Apex, or the API. |
isDelete | Returns true if this trigger was fired due to a delete operation, from the Salesforce user interface, Apex, or the API. |
isBefore | Returns true if this trigger was fired before any record was saved. |
isAfter | Returns true if this trigger was fired after all records were saved. |
isUndelete | Returns true if this trigger was fired after a record is recovered from the Recycle Bin. This recovery can occur after an undelete operation from the Salesforce user interface, Apex, or the API. |
new | Returns a list of the new versions of the sObject records. This sObject list is only available in insert, update, and undelete triggers, and the records can only be modified in before triggers. |
newMap | A map of IDs to the new versions of the sObject records. This map is only available in before update, after insert, after update, and after undelete triggers. |
old | Returns a list of the old versions of the sObject records. This sObject list is only available in update and delete triggers. |
oldMap | A map of IDs to the old versions of the sObject records. This map is only available in update and delete triggers. |
operationType | Returns an enum of type System.TriggerOperation corresponding to the current operation. Possible values of the System.TriggerOperation enum are: BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE,AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, and AFTER_UNDELETE. If you vary your programming logic based on different trigger types, consider using the switch statement with different permutations of unique trigger execution enum states. |
size | The total number of records in a trigger invocation, both old and new. |
When ever the Account is created with the Industry field as "IT" then create a contact for the account, use the Contact "Lastname" value from the Account name and the contact phone from account phone.
trigger CreateContactOnAccountCreation on Account (before insert) {
// Loop through the list of accounts being inserted
for (Account acc : Trigger.new) {
// Check if the account's Industry field is set to "IT" if (acc.Industry == 'IT') {
// Create a new contact record Contact contact = new Contact();
// Set the Lastname field to the account name contact.LastName = acc.Name;
// Set the Phone field to the account phone contact.Phone = acc.Phone;
// Set the AccountId field to the ID of the account being inserted contact.AccountId = acc.Id;
// Add the contact to the list of records to be inserted insert contact;
}
}
}
Check out another amazing blog by Aman here: Apex Trigger Scenarios | All You Need to Know
Write a trigger on the account to count all the accounts with their respective countries
trigger CountAccountsByCountry on Account (after insert, after update, after delete, after undelete) {
// Query for all the distinct countries where accounts are located Set<String> countries = new Set<String>();
for (Account acc : [SELECT BillingCountry FROM Account]) {
countries.add(acc.BillingCountry); }
// Create a map to store the counts for each country Map<String, Integer> counts = new Map<String, Integer>();
// Initialize the counts to 0 for each country for (String country : countries) { counts.put(country, 0);
}
// Query for all the accounts and update the counts
for (Account acc : [SELECT Id, BillingCountry FROM Account]) {
counts.put(acc.BillingCountry, counts.get(acc.BillingCountry) + 1); }
// Update the custom field on the Account object with the counts for each country List<Account> accountsToUpdate = new List<Account>();
for (String country : counts.keySet()) {
Account acc = new Account(); acc.BillingCountry = country; acc.Accounts_in_Country__c = counts.get(country); accountsToUpdate.add(acc); }
update accountsToUpdate;
}
How to check the old value in the field using a trigger?
trigger MyTrigger on MyObject__c (before update) { for (MyObject__c obj : Trigger.old) { // Check the old value of a field if (obj.FieldName__c != Trigger.oldMap.get(obj.Id).FieldName__c) { // Field value has changed // Perform desired actions here } } }
1000 records are being processed through a Batch to update any object like Account. Write code to maintain how many records failed to be updated.
trigger AccountTrigger on Account (before update) {
// Declare a variable to store the count of failed records Integer failedRecordCount = 0;
// Loop through the records in the trigger context for (Account account : Trigger.new) {
// Check if the record is in an error state if (account.isValid() == false) {
// If the record is in an error state, increment the failed record count failedRecordCount++;
}
}
// Save the failed record count in a custom field on the object for (Account account : Trigger.new) {
account.Failed_Record_Count__c = failedRecordCount;
}
}
Make a field on account object "No of Total Contact". Write a trigger to count the total no of contact associated with the particular account when the contact is inserted or deleted.
trigger ContactTrigger on Contact (after insert, after delete) {
// Get the list of account IDs for the inserted or deleted contacts Set<Id> accountIds = new Set<Id>();
for (Contact contact : Trigger.new) {
accountIds.add(contact.AccountId);
}
// Query for the accounts with the matching IDs List<Account> accounts = [ SELECT Id, No_of_Total_Contacts__c FROM Account WHERE Id IN :accountIds ];
// Loop through the accounts and update the "No of Total Contacts" field
for (Account account : accounts) {
account.No_of_Total_Contacts__c = [ SELECT COUNT() FROM Contact WHERE AccountId = :account.Id ];
}
// Update the accounts with the new contact count update accounts;
}
Account has 10 opportunity links to them. The owner changed the email field to any one of the one opportunity It will update all the sibling's opportunities with the same account.
trigger AccountTrigger on Account (before update) {
// Get the list of account IDs that have been updated Set<Id> accountIds = new Set<Id>();
for (Account account : Trigger.new) {
accountIds.add(account.Id);
}
// Query for the opportunities with matching account IDs
List<Opportunity> opportunities = [ SELECT Id, AccountId, Email__c FROM Opportunity WHERE AccountId IN :accountIds ];
// Loop through the opportunities and update the email field
for (Opportunity opportunity : opportunities) {
// Find the corresponding account for the opportunity Account
account = Trigger.oldMap.get(opportunity.AccountId);
// Update the email field on the opportunity opportunity.Email__c = account.Email;
}
// Update the opportunities with the new email field value update opportunities;
}
When the user is deactivated then it's related Accounts and opportunity will automatically assign to its manager.
trigger UserTrigger on User (before update) {
// Get the list of user IDs that have been updated Set<Id> userIds = new Set<Id>();
for (User user : Trigger.new) {
userIds.add(user.Id);
}
// Query for the users with the matching IDs List<User>
users = [ SELECT Id, IsActive, ManagerId FROM User WHERE Id IN :userIds ];
// Create a map of user IDs to managers Map<Id, Id> userManagerMap = new Map<Id, Id>();
for (User user : users) {
userManagerMap.put(user.Id, user.ManagerId);
}
// Query for the accounts and opportunities with matching owner IDs List<Account> accounts = [ SELECT Id, OwnerId FROM Account WHERE OwnerId IN :userIds ];
List<Opportunity> opportunities = [ SELECT Id, OwnerId FROM Opportunity WHERE OwnerId IN :userIds ];
// Loop through the accounts and opportunities and update the owner field
for (Account account : accounts) {
account.OwnerId = userManagerMap.get(account.OwnerId);
}
for (Opportunity opportunity : opportunities) {
opportunity.OwnerId = userManagerMap.get(opportunity.OwnerId);
}
// Update the accounts and opportunities with the new owner field value update accounts; update opportunities;
}
Thanks for provide great informatic and looking beautiful blog, really nice required information & the things i never
imagined and i would request, wright more blog and blog post like that for us. Thanks you once again..
salesforce-course-in-hyderabad