Use an If Condition: Check if the lead source equals "Web" before assigning the lead to the queue.
Example:
if (lead.LeadSource == 'Web') {
lead.OwnerId = queueId;
update lead;
}
• Purpose: Directs the lead to the appropriate owner based on its source.
• Use an If Condition: Check if the field is not null before accessing it.
Example:
if (contact.Email != null) {
System.debug('Email: ' + contact.Email);
}
• Purpose: Avoids runtime errors by ensuring the field is not null before use.
• Use an If Condition: Check the record type before executing the corresponding logic.
Example:
if (opp.RecordType.Name == 'Enterprise') {
// Logic for Enterprise
} else if (opp.RecordType.Name == 'SMB') {
// Logic for SMB
}
• Purpose: Tailors the logic based on the specific record type of the opportunity.
• Use an If Condition: Check the case status before allowing updates.
Example:
if (caseRecord.Status != 'Closed') {
update caseRecord;
}
• Purpose: Ensures that closed cases are not inadvertently updated.
Use an If Condition: Compare the last activity date with the current date before sending the email.
Example:
if (contact.LastActivityDate < Date.today().addDays(-30)) {
// Send email
}
• Purpose: Ensures emails are sent only when the condition is met, avoiding unnecessary alerts.
• Use an If Condition Within a Loop: Check if there are related opportunities before processing the account.
Example:
for (Account acc : accounts) {
if (acc.Opportunities.size() > 0) {
// Process account
}
}
• Purpose: Optimises processing by skipping irrelevant records.
• Use a for Loop: Iterate through the list of contacts and update the field within the loop.
Example:
List<Contact> contacts = [SELECT Id, Email_Opt_Out__c FROM Contact];
for (Contact c : contacts) {
c.Email_Opt_Out__c = true;
}
update contacts;
• Purpose: Efficiently processes each record in the list and updates the specified field.
Use a for Loop: Sum the amounts of all opportunities related to the account within the loop.
Example:
Decimal totalAmount = 0;
List<Opportunity> opps = [SELECT Amount FROM Opportunity WHERE AccountId = :accountId];
for (Opportunity opp : opps) {
totalAmount += opp.Amount;
}
• Purpose: Aggregates data across multiple records to provide a cumulative value.
• Use Nested for Loops: Loop through accounts and then loop through each account’s contacts.
Example:
List<Account> accounts = [SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account];
for (Account acc : accounts) {
for (Contact con : acc.Contacts) {
System.debug('Account: ' + acc.Name + ', Contact: ' + con.Name);
}
}
• Purpose: Efficiently processes parent-child data structures in Salesforce.
Use a Conditional continue Statement: Use continue to skip to the next iteration if the condition is met.
Example:
for (Account acc : accounts) {
if (acc.Contacts.isEmpty()) {
continue;
}
// Process accounts with contacts
}
• Purpose: Optimizes loop processing by skipping irrelevant records.
• Use a Conditional continue Statement: Use continue to skip to the next iteration if the condition is met.
Example:
for (Account acc : accounts) {
if (acc.Contacts.isEmpty()) {
continue;
}
// Process accounts with contacts
}
• Purpose: Optimizes loop processing by skipping irrelevant records.
• Use a break Statement: Exit the loop when the condition is satisfied.
Example:
for (Opportunity opp : opps) {
if (opp.Amount > 100000) {
System.debug('High-value opportunity found: ' + opp.Name);
break;
}
}
• Purpose: Improves efficiency by stopping further iterations once the desired condition is met.
• Use a for Loop with Set: Loop through the Set to process each unique value.
Example:
Set<String> productCodes = new Set<String>{'P001', 'P002', 'P003'};
for (String code : productCodes) {
System.debug('Processing product code: ' + code);
}
• Purpose: Handles collections of unique values effectively.
• Use a for Loop with Map Entries: Loop through the Map using Map.Entry.
Example:
Map<Id, String> accountMap = new Map<Id, String>{};
for (Map<Id, String>.Entry entry : accountMap.entrySet()) {
System.debug('Account ID: ' + entry.getKey() + ', Account Name: ' +
entry.getValue());
}
• Purpose: Allows access to both the key and value in a Map.
• Use a for Loop with Subsets: Break the list into smaller batches and process each separately.
Example:
Integer batchSize = 100;
for (Integer i = 0; i < allRecords.size(); i += batchSize) {
List<SObject> batch = allRecords.subList(i, Math.min(i +
batchSize, allRecords.size()));
// Process each batch
}
• Purpose: Ensures efficient processing without exceeding Salesforce governor limits.
• Use an Array: Declare an array of strings to store the account names.
Example:
String[] accountNames = new String[] {'Acme Corp', 'Global Media', 'Tech Solutions'};
for (Integer i = 0; i < accountNames.size(); i++) {
System.debug('Account Name: ' + accountNames[i]);
}
• Purpose: Arrays are used to store multiple values of the same data type and iterate through them for processing.
• Use ArrayList: Use a dynamic array (List) to add email addresses as they are retrieved.
Example:
String[] emailAddresses = new String[]{};
for (Contact c : [SELECT Email FROM Contact WHERE AccountId = :accountId])
{
emailAddresses.add(c.Email);
}
• Purpose: Dynamically build an array when the number of elements isn’t known beforehand.
• Filter Array: Iterate through the array and remove elements that meet the criteria.
Example:
Integer[] numbers = new Integer[]{1, null, 2, null, 3};
numbers.removeAll(new List<Integer>{null});
• Purpose: Clean up an array by removing unwanted or null elements.
• Use Sorting: Utilize the sort() method with a custom comparator for descending order.
Example:
Decimal[] amounts = new Decimal[]{1000, 5000, 2000};
amounts.sort();
amounts.reverse();
System.debug(amounts);
• Purpose: Order array elements to meet specific sorting requirements.
• Use addAll: Combine two arrays using the addAll() method.
Example:
String[] array1 = new String[]{'Acme', 'Global Media'};
String[] array2 = new String[]{'Tech Solutions', 'Innovate LLC’};
array1.addAll(array2);
System.debug(array1);
• Purpose: Merge multiple arrays into one for combined processing.
• Use contains: Check for the presence of a value in the array using contains().
Example:
String[] accountNames = new String[]{'Acme Corp', 'Global Media', 'Tech Solutions'};
if (accountNames.contains('Acme Corp')) {
System.debug('Acme Corp exists in the array');
}
• Purpose: Determine whether a specific value is present in an array.
• Use toArray: Convert a List to an array using the toArray() method.
Example:
List<String> opportunityNames = new List<String>{'Opportunity A', 'Opportunity B'};
String[] oppArray = opportunityNames.toArray(new String[]{});
• Purpose: Utilize array operations on data initially stored in a List.
• Use a List: Store the query results in a List<Contact> and then process them.
Example:
List<Contact> contacts = [SELECT Id, Name, Email FROM Contact WHERE
AccountId = :accountId];
for (Contact c : contacts) {
System.debug('Contact Name: ' + c.Name);
}
• Purpose: Lists are used to hold multiple records retrieved from a SOQL query for further processing.
• Use add Method: Use the add() method to dynamically add elements to the List.
Example:
List<String> oppNames = new List<String>();
for (Opportunity opp : [SELECT Name FROM Opportunity WHERE Amount > 50000])
{
oppNames.add(opp.Name);
}
• Purpose: Dynamically build a List when the number of elements is not predetermined.
• Use a Loop and remove Method: Iterate through the List and remove items that meet the condition.
Example:
List<Task> tasks = [SELECT Id, Status FROM Task WHERE Status = 'Completed'];
for (Integer i = tasks.size() - 1; i >= 0; i--) {
if (tasks[i].Status == 'Completed') {
tasks.remove(i);
}}
• Purpose: Clean up a List by removing unwanted or completed tasks.
Use contains Method: Use the contains() method to check for the presence of an element.
Example:
List<String> accNames = new List<String>{'Acme Corp','Global Media',‘Tech Solutions'};
if (accNames.contains('Acme Corp')) {
System.debug('Acme Corp exists in the list.');
}
• Purpose: Quickly check if a specific value is present in a List.
Use sort() Method: Use the sort() method and then reverse the List to sort in descending order.
Example:
List<Integer> salesFigures = new List<Integer>{1000, 5000, 2000};
salesFigures.sort();
salesFigures.reverse();
System.debug(salesFigures);
• Purpose: Order List elements based on specific sorting requirements.
Use a Loop: Iterate through the List to identify the maximum value.
Example:
Decimal maxAmount = 0;
List<Opportunity> opps = [SELECT Amount FROM Opportunity];
for (Opportunity opp : opps) {
if (opp.Amount > maxAmount) {
maxAmount = opp.Amount;
}
}
System.debug('Maximum Amount: ' + maxAmount);
• Purpose: Identify the highest value in a collection of records.
Use addAll Method: Combine the Lists using the addAll() method.
Example:
List<String> list1 = new List<String>{'John Doe', 'Jane Smith'};
List<String> list2 = new List<String>{'Alice Brown', 'Bob White’};
list1.addAll(list2);
System.debug(list1);
• Purpose: Merge multiple Lists into one for combined processing.
Example:
List<String> emailList = new List<String>{'test@example.com', 'user@example.com', 'test@example.com'};
Set<String> emailSet = new Set<String>(emailList);
System.debug(emailSet);
Use subList() Method: Break down the List into smaller batches and process each separately.
Example:
List<Account> accounts = [SELECT Id, Name FROM Account];
Integer batchSize = 100;
for (Integer i = 0; i < accounts.size(); i += batchSize) {
List<Account> batch = accounts.subList(i, Math.min(i + batchSize,
accounts.size()));
// Process each batch
}
• Purpose: Efficiently handle large data sets by processing in manageable chunks to avoid hitting governor limits.
Example:
Set<String> uniqueEmails = new Set<String>();
for (Lead lead : [SELECT Email FROM Lead WHERE CampaignId = :campaignId]) {
uniqueEmails.add(lead.Email);
}
• Purpose: A Set automatically removes duplicates, ensuring only unique email addresses are processed.
Use contains Method: Use the contains() method to check if the Set includes the product code.
Example:
Set<String> productCodes = new Set<String>{'P001', 'P002', 'P003'};
if (productCodes.contains('P002')) {
System.debug('Product code P002 exists.');
}
• Purpose: Efficiently checks for the presence of a value within a collection.
Convert List to Set: Use a Set to automatically remove duplicates from the list.
Example:
List<String> emailList = new List<String>{'test@example.com', 'user@example.com', 'test@example.com'};
Set<String> uniqueEmails = new Set<String>(emailList);
• Purpose: Convert a List to a Set to ensure all values are unique.
Use retainAll Method: Use the retainAll() method to find the intersection of two Sets.
Example:
Set<Id> set1 = new Set<Id>{'001xx000003DGbX', '001xx000003DGbY'};
Set<Id> set2 = new Set<Id>{'001xx000003DGbY', '001xx000003DGbZ'};
set1.retainAll(set2);
System.debug('Common Account IDs: ' + set1);
• Purpose: Finds and retains only the common elements between two Sets.
Use retainAll Method: Use the retainAll() method to find the intersection of two Sets.
Example:
Set<Id> set1 = new Set<Id>{'001xx000003DGbX', '001xx000003DGbY'};
Set<Id> set2 = new Set<Id>{'001xx000003DGbY', '001xx000003DGbZ'};
set1.retainAll(set2);
System.debug('Common Account IDs: ' + set1);
• Purpose: Finds and retains only the common elements between two Sets.
Use a Conditional Check: Use an if statement within a loop to add values to the Set conditionally.
Example:
Set<Id> activeUserIds = new Set<Id>();
for (User user : [SELECT Id FROM User WHERE IsActive = true]) {
activeUserIds.add(user.Id);
}
• Purpose: Add elements to a Set based on specific conditions.
Use remove Method: Use the remove() method to delete elements from the Set.
Example:
Set<Id> userIds = new Set<Id>{/* some user IDs */};
for (User user : [SELECT Id FROM User WHERE IsActive = false]) {
userIds.remove(user.Id);
}
• Purpose: Removes elements from a Set based on certain criteria.
• Convert Set to List: Use the List constructor to convert the Set.
Example:
Set<String> accountNamesSet = new Set<String>{'Acme Corp', 'Global Media'};
List<String> accountNamesList = new List<String>(accountNamesSet);
System.debug(accountNamesList);
• Purpose: Convert a Set to a List when order and indexing are needed.
Store IDs in Set: Use a Set to store unique contact IDs for deletion.
Example:
Set<Id> contactIdsToDelete = new Set<Id>();
for (Contact c : [SELECT Id, Email FROM Contact WHERE Email IN :duplicateEmails]) {
contactIdsToDelete.add(c.Id);
}
delete contactIdsToDelete;
• Purpose: Efficiently perform bulk deletion by ensuring no duplicates are processed.
Store Processed IDs in a Set: Use a Set to keep track of processed opportunity IDs and check against it.
Example:
Set<Id> processedOppIds = new Set<Id>{/* some processed IDs */};
for (Opportunity opp : [SELECT Id, Name FROM Opportunity]) {
if (!processedOppIds.contains(opp.Id)) {
// Process the opportunity
processedOppIds.add(opp.Id);
} }
• Purpose: Use a Set for efficient lookups to avoid re-processing records.
Use a Map: Create a Map<String, Account> where the key is the account name and the value is the Account record.
Example:
Map<String, Account> accountMap = new Map<String, Account>();
for (Account acc : [SELECT Id, Name FROM Account]) {
accountMap.put(acc.Name, acc);
}
• Purpose: This allows quick retrieval of account records based on the account name.
Use a Map: Create a Map<Id, Decimal> to store the aggregated opportunity amount by account ID.
Example:
Map<Id, Decimal> accountTotals = new Map<Id, Decimal>();
for (Opportunity opp : [SELECT AccountId, Amount FROM Opportunity]) {
if (accountTotals.containsKey(opp.AccountId)) {
accountTotals.put(opp.AccountId, accountTotals.get(opp.AccountId) +
opp.Amount);
} else {
accountTotals.put(opp.AccountId, opp.Amount);
}
}
• Purpose: Aggregates data where the key is an account and the value is the total opportunity amount.
Use a Map: Create a Map<Id, CustomObject__c> to store custom object records, keyed by
the related contact ID.
Example:
Map<Id, CustomObject__c> customObjMap = new Map<Id, CustomObject__c>();
for (CustomObject__c obj : [SELECT Id, Contact__c, Field__c FROM
CustomObject__c]) {
customObjMap.put(obj.Contact__c, obj);
}
for (Contact con : [SELECT Id, Name FROM Contact WHERE Id
IN :customObjMap.keySet()]) {
con.Field__c = customObjMap.get(con.Id).Field__c;
}
update con;
• Purpose: Efficiently update records by leveraging data stored in a Map.
Use a Map with List Values: Create a Map<String, List<Contact>> where the key is the account name and the value is a list of contacts.
Example:
Map<String, List<Contact>> accountContactsMap = new Map<String, List<Contact>>();
for (Contact con : [SELECT Id, Name, Account.Name FROM Contact]) {
if (!accountContactsMap.containsKey(con.Account.Name)) {
accountContactsMap.put(con.Account.Name, new List<Contact>());
}
accountContactsMap.get(con.Account.Name).add(con);
}
• Purpose: Manage multiple values under a single key by storing lists within the Map.
Use a Map: Create a Map<Id, String> to map account IDs to account names, and then use this Map while processing opportunities.
Example:
Map<Id, String> accountNameMap = new Map<Id, String>();
for (Account acc : [SELECT Id, Name FROM Account]) {
accountNameMap.put(acc.Id, acc.Name);
}
for (Opportunity opp : [SELECT Id, AccountId FROM Opportunity]) {
System.debug('Opportunity Account: ' +
accountNameMap.get(opp.AccountId));
}
• Purpose: Easily access related data across multiple objects using a Map.
Use a Map: Query related data once and store it in a Map, then use this Map to process records without additional queries.
Example:
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account WHERE
Industry = 'Technology']);
for (Opportunity opp : [SELECT Id, AccountId FROM Opportunity WHERE Amount > 100000]) {
Account acc = accountMap.get(opp.AccountId);
if (acc != null) {
System.debug('Processing Opportunity for Account: ' + acc.Name);
}
}
• Purpose: Reduces SOQL queries by storing and reusing data in a Map.
• Use Multiple Maps: Create Maps for each object, then merge the data as needed.
Example:
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);
Map<Id, Opportunity> oppMap = new Map<Id, Opportunity>([SELECT Id, AccountId FROM Opportunity]);
for (Id accId : accountMap.keySet()) {
if (oppMap.containsKey(accId)) {
System.debug('Account: ' + accountMap.get(accId).Name + ', Opportunity: ' + oppMap.get(accId).Name);
}
}
• Purpose: Combine data from different sources for comprehensive analysis.
Use remove Method: Iterate through the Map and remove entries that don’t meet the criteria.
Example:
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);
for (Id accId : new Map<Id, Account>(accountMap).keySet()) {
if (!oppMap.containsKey(accId)) { // Assuming oppMap holds active opportunities
accountMap.remove(accId);
}
}
• Purpose: Clean up a Map by removing entries that are not relevant.
Method Parameter: Define the method to accept a Map as a parameter and pass the Map to it.
Example:
public void processAccounts(Map<Id, String> accountMap) {
for (Id accId : accountMap.keySet()) {
System.debug('Processing Account: ' + accountMap.get(accId));
}
}
Map<Id, String> accounts = new Map<Id, String>{/* account data */};
processAccounts(accounts);
• Purpose: Use Maps as method parameters to handle complex data structures.
SOQL Query:
SELECT Id, Name FROM Account WHERE IsActive__c = true
• Explanation: This query filters accounts based on the custom IsActive__c field, retrieving only those that are marked as active.
SOQL Query:
SELECT Id, Name, Email FROM Contact WHERE Email LIKE ‘%@example.com'
• Explanation: The LIKE operator is used with the % wildcard to match any contact email that ends with @example.com.
SOQL Query:
SELECT Id, CaseNumber FROM Case WHERE CreatedDate = LAST_N_DAYS:30
• Explanation: The LAST_N_DAYS function filters cases based on their creation date, retrieving those created in the past 30 days.
SOQL Query:
SELECT Id, Name FROM Account WHERE RecordType.Name = ‘Customer'
• Explanation: This query filters accounts by the RecordType.Name field, returning only those with the record type “Customer".
SOQL Query:
SELECT Id, Name, Amount FROM Opportunity WHERE Amount >= 10000 AND Amount <= 50000
• Explanation: The WHERE clause uses the AND operator to filter opportunities within the specified amount range.
SOQL Query:
SELECT Id, CaseNumber FROM Case WHERE Status = 'Open' AND Priority = ‘High'
• Explanation: The query uses the AND operator to filter cases that are both open and have a high priority.
SOQL Query:
SELECT Id, Name FROM Opportunity WHERE Account.Industry = ‘Technology'
• Explanation: This query filters opportunities based on a field (Industry) from a related object (Account), returning those associated with accounts in the technology industry.
SOQL Query:
SELECT Id, Name FROM Account LIMIT 10
• Explanation: The LIMIT keyword restricts the number of records returned by the query to 10, useful for displaying a subset of data.
SOQL Query:
SELECT Id, Name FROM Opportunity LIMIT 20 OFFSET 40
• Explanation: The OFFSET keyword is used with LIMIT to skip the first 40 records and then retrieve the next 20, useful for pagination.
SOQL Query:
SELECT Id, Name FROM Contact WHERE IsDeleted = true ALL ROWS
• Explanation: The ALL ROWS keyword retrieves both active and deleted records, allowing you to include records in the Recycle Bin in your results.
SOQL Query:
SELECT Id, Name, Amount FROM Opportunity ORDER BY Amount DESC LIMIT 5
• Explanation: The ORDER BY clause sorts the opportunities by amount in descending order, and LIMIT restricts the results to the top 5.
SOQL Query:
SELECT Id, Name FROM Account WHERE IsDeleted = true ORDER BY LastModifiedDate DESC LIMIT 3 ALL ROWS
• Explanation: This query uses ORDER BY and LIMIT in conjunction with ALL ROWS to retrieve the 3 most recently deleted accounts.
SOQL Query:
SELECT Id, Name FROM Account ORDER BY CreatedDate ASC LIMIT 5
• Explanation: The ORDER BY CreatedDate ASC clause sorts the records by creation date in ascending order, and LIMIT restricts the results to the oldest 5 records.
SOQL Query:
SELECT Id, Name, Amount FROM Opportunity WHERE Amount > 1000000 ALL ROWS
• Explanation: The ALL ROWS keyword allows you to retrieve both active and deleted opportunities that meet the specified criteria.
SOQL Query:
SELECT StageName, COUNT(Id) FROM Opportunity GROUP BY StageName
• Explanation: The GROUP BY clause groups opportunities by their stage name, and COUNT(Id) returns the number of opportunities in each stage.
SOQL Query:
SELECT StageName, COUNT(Id) FROM Opportunity GROUP BY StageName HAVING COUNT(Id) > 10
• Explanation: The HAVING clause filters the grouped results to include only those stages with more than 10 opportunities.
SOQL Query:
SELECT Id, Name FROM Account WHERE Industry = 'Technology' FOR UPDATE
• Explanation: The FOR UPDATE keyword locks the selected records, preventing other transactions from modifying them until your transaction completes.
SOQL Query:
SELECT StageName, CloseDate, COUNT(Id) FROM Opportunity GROUP BY StageName, CloseDate
• Explanation: The GROUP BY clause groups opportunities first by stage and then by close date, allowing you to see counts for each combination.
SOQL Query:
SELECT AccountId, COUNT(Id) FROM Opportunity WHERE Amount > 50000 GROUP BY AccountId HAVING COUNT(Id) > 5
• Explanation: The query groups opportunities by account and filters the groups to include only those accounts with more than 5 opportunities exceeding $50,000.
SOQL Query:
SELECT AccountId, SUM(Amount) FROM Opportunity GROUP BY AccountId ORDER BY SUM(Amount) DESC
• Explanation: The ORDER BY clause sorts the grouped results based on the total opportunity amount in descending order.
SOQL Query:
SELECT Id, CaseNumber FROM Case ORDER BY CreatedDate DESC OFFSET 4 LIMIT 11
• Explanation: The OFFSET 4 skips the first 4 cases, and LIMIT 11 retrieves the next 11, giving you the 5th to 15th records.
SOQL Query:
SELECT Id, Name FROM Account ORDER BY Name OFFSET 0 LIMIT 100
• Explanation: Start with OFFSET 0 LIMIT 100 for the first page, and increment the OFFSET for subsequent pages to retrieve the next sets of 100 records.
Dynamic SOQL Example:
String searchTerm = 'Smith';
String query = 'SELECT Id, Name FROM Contact WHERE LastName LIKE \'%' + searchTerm + '%\'';
List<Contact> contacts = Database.query(query);
• Explanation: This code constructs a SOQL query string dynamically using the user's input and then executes it using Database.query().
Dynamic SOQL Example:
String objectName = 'Account';
String query = 'SELECT Id, Name FROM ' + objectName + ' LIMIT 10';
List<SObject> records = Database.query(query);
• Explanation: The object name is dynamically inserted into the SOQL query, allowing the same code to retrieve records from various objects.
Dynamic SOQL Example:
String baseQuery = 'SELECT Id, Name FROM Account WHERE ';
String conditions = '';
if (industry != null) conditions += 'Industry = \'' + industry + '\'';
if (annualRevenue != null) {
if (conditions != '') conditions += ' AND ‘;
conditions += 'AnnualRevenue > ' + annualRevenue;
}
String finalQuery = baseQuery + conditions;
List<Account> accounts = Database.query(finalQuery);
• Explanation: The query string is dynamically built by appending conditions only if the corresponding variables are not null.
Dynamic SOQL Example:
String sortBy = 'CreatedDate';
String query = 'SELECT Id, Name FROM Opportunity ORDER BY ' + sortBy + ' DESC';
List<Opportunity> opportunities = Database.query(query);
• Explanation: The field to sort by is determined at runtime based on user input, allowing for flexible query construction.
Dynamic SOQL Example:
String query = 'SELECT Id, Name FROM Contact WHERE 1=1';
if (firstName != null) query += ' AND FirstName = \'' + firstName + '\'';
if (lastName != null) query += ' AND LastName = \'' + lastName + '\'';
if (email != null) query += ' AND Email = \'' + email + '\'';
List<Contact> contacts = Database.query(query);
• Explanation: The query starts with a base WHERE clause (1=1), and additional conditions are appended based on non-null inputs.
Dynamic SOQL Example:
String fieldName = 'CloseDate';
Date dateValue = Date.today().addDays(-30);
String query = 'SELECT Id, Name FROM Opportunity WHERE ' + fieldName + ' >= ' + dateValue.format();
List<Opportunity> opportunities = Database.query(query);
• Explanation: This example demonstrates how to dynamically handle date fields, converting the Date object to a string using format() for insertion into the query.
Dynamic SOQL Example:
String query = 'SELECT Id, Name FROM Lead WHERE IsConverted = false’;
if (leadSource != null) {
query += ' AND LeadSource = \'' + leadSource + '\'';
}
List<Lead> leads = Database.query(query);
• Explanation: The base query is static, but additional conditions are appended dynamically based on input variables.
Dynamic SOQL Example:
String relatedObject = 'Contacts';
String query = 'SELECT Id,Name,(SELECT LastName FROM '+relatedObject + ') FROM Account';
List<Account> accounts = Database.query(query);
• Explanation: This query dynamically inserts the related object into the query string, allowing for flexible retrieval of related records.
SOQL Query:
SELECT Id, Name,(SELECT Id, Name FROM Contacts) FROM Account WHERE Id = ‘001xx000003DGbX'
• Explanation: This query retrieves the account with a specific ID and all related contacts. The Contacts relationship name is used in the subquery to fetch child records.
SOQL Query:
SELECT Id, Name, (SELECT Id, Name, StageName FROM Opportunities) FROM Account WHERE Id IN ('001xx000003DGbX', ‘001xx000003DGbY')
• Explanation: The subquery (SELECT Id, Name, StageName FROM Opportunities) fetches all related opportunities for the specified accounts.
SOQL Query:
SELECT Id, Name, (SELECT Id, Name, Status__c FROM Tasks__r) FROM Project__c
• Explanation: The subquery fetches all related Task__c child records using the relationship name Tasks__r.
SOQL Query:
SELECT Id, Name, (SELECT Id, Product__c, Quantity__c FROM OrderItems__r WHERE Quantity__c > 10) FROM Order__c
• Explanation: The subquery fetches related OrderItem__c records where the quantity exceeds 10.
SOQL Query:
SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account WHERE Industry = ‘Technology'
• Explanation: The query filters accounts by industry and retrieves all related contacts.
SOQL Query:
SELECT Id, Name, Account.Name, Account.Industry FROM Contact
• Explanation: This query retrieves contact details and uses the relationship to the Account object to fetch the account name and industry for each contact.
SOQL Query:
SELECT Id, Name, Project__r.Name, Project__r.Status__c FROM Task__c
• Explanation: This query retrieves Task__c details and uses the relationship to the Project__c parent object to fetch the project name and status.
SOQL Query:
SELECT Id, Name, Course__r.Name, Course__r.Credits__c FROM Enrollment__c
• Explanation: The query retrieves Enrollment__c records and uses the relationship to fetch related Course__c details.
SOQL Query:
SELECT Id, Quantity__c, Order__r.Name, Order__r.Status__c FROM OrderLineItem__c WHERE Order__r.Status__c = ‘Shipped'
• Explanation: The query retrieves OrderLineItem__c records and fetches details from the related Order__c where the status is "Shipped".
SOQL Query:
SELECT Id, CaseNumber, Account.Name, Account.Parent.Industry FROM Case
• Explanation: This query retrieves case details, the related account's name, and the industry of the parent account through the relationship chain.
SOSL Query:
FIND 'Acme' IN ALL FIELDS RETURNING Account(Id, Name), Contact(Id, FirstName, LastName), Opportunity(Id, Name)
• Explanation: This SOSL query searches for the keyword "Acme" in all fields across the Account, Contact, and Opportunity objects and returns specified fields from each.
SOSL Query:
FIND 'Acme*' IN NAME FIELDS RETURNING Account(Id, Name)
• Explanation: The asterisk (*) is used as a wildcard in SOSL to search for all account names starting with “Acme”.
SOSL Query:
FIND 'Acme OR Global' IN ALL FIELDS RETURNING Account(Id, Name), Contact(Id, FirstName, LastName)
• Explanation: The OR operator in SOSL allows you to search for multiple keywords across all fields.
Example Query:
FIND 'john doe' IN ALL FIELDS RETURNING Contact(Id, FirstName, LastName)
• Explanation: SOSL searches are inherently case-insensitive, so a query like FIND 'john doe' will match John Doe, JOHN DOE, etc.
SOSL Query:
FIND '*@example.com' IN EMAIL FIELDS RETURNING Contact(Id, FirstName, LastName, Email)
• Explanation: The wildcard * is used to search for any email address containing the domain "example.com".
Example:
List<Contact> contacts = new List<Contact>{
new Contact(FirstName = 'John', LastName = 'Doe', Email = 'john.doe@example.com'),
new Contact(FirstName = 'Jane', LastName = 'Doe', Email = 'jane.doe@example.com')
};
insert contacts;
• Explanation: This code creates a list of Contact objects and inserts them into Salesforce in a single DML operation using the insert keyword.
Example:
List<Contact> contactsToUpdate = [SELECT Id, Email FROM Contact WHERE LastName = 'Doe'];
for (Contact c : contactsToUpdate) {
c.Email = 'newemail@example.com';
}
update contactsToUpdate;
• Explanation: This query retrieves contacts with the last name "Doe," updates their email addresses, and performs a bulk update DML operation.
Example:
List<Case> casesToDelete = [SELECT Id FROM Case WHERE Status = 'Closed' AND CreatedDate < LAST_YEAR];
delete casesToDelete;
• Explanation: The query fetches closed cases older than a year, and the delete keyword removes them in a single DML operation.
Example:
Database.SaveResult[] results = Database.insert(contactsToInsert, false);
for (Database.SaveResult result : results) {
if (result.isSuccess()) {
System.debug('Record inserted: ' + result.getId());
} else {
System.debug('Error: ' + result.getErrors()[0].getMessage());
}}
• Explanation: This approach uses Database.insert with allOrNone set to false, allowing partial success and handling errors for individual records.
Example:
Database.DMLOptions dmlOpts = new Database.DMLOptions();
dmlOpts.EmailHeader.triggerUserEmail = false;
dmlOpts.ValidationOptions.skipValidation = true;
Account newAccount = new Account(Name = 'Test Account');
Database.insert(newAccount, dmlOpts);
• Explanation: DML options are configured to bypass certain processes (e.g., email alerts, validation rules) during the insert operation.
Example:
try {
insert new Contact(FirstName = 'John', LastName = 'Doe');
} catch (DmlException e) {
System.debug('DML Exception: ' + e.getMessage());
}
• Explanation: The try-catch block handles any DmlException that occurs during the insert operation, allowing you to capture and log the error.
Example:
List<Contact> contactsToInsert = new List<Contact>{
new Contact(FirstName = 'John', LastName = 'Doe', Email = 'john.doe@example.com'),
new Contact(FirstName = null, LastName = 'Smith') // This will fail due to a
validation rule
};
Database.SaveResult[] results = Database.insert(contactsToInsert, false);
for (Database.SaveResult result : results) {
if (result.isSuccess()) {
System.debug('Record inserted: ' + result.getId());
} else {
System.debug('Error: ' + result.getErrors()[0].getMessage());
}
}
• Explanation: The Database.insert method with false for allOrNone allows partial success, inserting valid records and handling errors for failed records individually.
Example:
List<Account> accountsToUpdate = [SELECT Id, Name FROM Account WHERE Name LIKE 'Test%'];
for (Account acc : accountsToUpdate) {
acc.Name = 'Updated ' + acc.Name;
}
Database.SaveResult[] results = Database.update(accountsToUpdate, false);
for (Database.SaveResult result : results) {
if (!result.isSuccess()) {
for (Database.Error error : result.getErrors()) {
System.debug('Error updating account: ' + error.getMessage());
} } }
Explanation: The use of Database.update with partial success allows for error handling without interrupting the entire update process.
Example:
List<Case> casesToDelete = [SELECT Id FROM Case WHERE Status = 'Closed'];
Database.DeleteResult[] results = Database.delete(casesToDelete, false);
for (Database.DeleteResult result : results) {
if (!result.isSuccess()) {
System.debug('Error deleting case: ' + result.getErrors() [0].getMessage());
}
}
• Explanation: The Database.delete method allows for partial success, deleting records while continuing the operation even if some deletions fail.
Example:
List<Account> accountsToLock = [SELECT Id, Name FROM Account WHERE Industry = 'Technology' FOR UPDATE];
for (Account acc : accountsToLock) {
acc.Name = 'Locked ' + acc.Name;
}
Database.update(accountsToLock);
• Explanation: The FOR UPDATE keyword locks the selected records, preventing other transactions from modifying them until the current transaction is complete.
Example:
Account parentAccount = [SELECT Id, Name, (SELECT Id, LastName FROM Contacts) FROM
Account WHERE Name = 'Global Media'];
parentAccount.Name = 'Global Media Group';
List<Contact> relatedContacts = parentAccount.Contacts;
for (Contact c : relatedContacts) {
c.LastName = 'Updated ' + c.LastName;
}
Database.update(new List<SObject>{parentAccount}.addAll(relatedContacts), false);
• Explanation: This approach updates the parent account and all related contacts in a single Database.update operation, allowing for error handling.
Example:
Savepoint sp = Database.setSavepoint();
try {
Account newAccount = new Account(Name = 'Test Account');
Database.insert(newAccount);
Contact newContact = new Contact(LastName = 'Test', AccountId =
newAccount.Id);
Database.insert(newContact);
} catch (DmlException e) {
Database.rollback(sp);
System.debug('Transaction rolled back due to error: ' + e.getMessage());
}
• Explanation: The use of Database.update with partial success allows for error handling without interrupting the entire update process.
Example:
List<Case> casesToDelete = [SELECT Id FROM Case WHERE Status = 'Closed'];
Database.DeleteResult[] results = Database.delete(casesToDelete, false);
for (Database.DeleteResult result : results) {
if (!result.isSuccess()) {
System.debug('Error deleting case: ' + result.getErrors() [0].getMessage());
}
}
• Explanation: The Database.delete method allows for partial success, deleting records while continuing the operation even if some deletions fail.
Example:
List<Account> accountsToLock = [SELECT Id, Name FROM Account WHERE Industry = 'Technology' FOR UPDATE];
for (Account acc : accountsToLock) {
acc.Name = 'Locked ' + acc.Name;
}
Database.update(accountsToLock);
• Explanation: The FOR UPDATE keyword locks the selected records, preventing other transactions from modifying them until the current transaction is complete.
Example:
Account parentAccount = [SELECT Id, Name, (SELECT Id, LastName FROM Contacts) FROM Account WHERE Name = 'Global Media'];
parentAccount.Name = 'Global Media Group';
List<Contact> relatedContacts = parentAccount.Contacts;
for (Contact c : relatedContacts) {
c.LastName = 'Updated ' + c.LastName;
}
Database.update(new List<SObject>{parentAccount}.addAll(relatedContacts), false);
• Explanation: This approach updates the parent account and all related contacts in a single Database.update operation, allowing for error handling.
Example:
Savepoint sp = Database.setSavepoint();
try {
Account newAccount = new Account(Name = 'Test Account');
Database.insert(newAccount);
Contact newContact = new Contact(LastName = 'Test', AccountId =
newAccount.Id);
Database.insert(newContact);
} catch (DmlException e) {
Database.rollback(sp);
System.debug('Transaction rolled back due to error: ' +
e.getMessage());
}
• Explanation: The Database.rollback method reverts the transaction to a savepoint, undoing all changes made after that point in case of an error.
Example:
Messaging.SingleEmailMessage mail= new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {'contact@example.com'});
mail.setSubject('New Case Created');
mail.setPlainTextBody('A new case has been created.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
• Explanation: This code sends a plain text email to the specified contact when a new case is created.
Example:
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTargetObjectId(opportunity.OwnerId);
mail.setTemplateId('00Xxx0000001ABc');
mail.setWhatId(opportunity.Id);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
• Explanation: The email is sent using a predefined template and is personalized based on the opportunity owner's information.
List<Contact> contacts = [SELECT Email FROM Contact WHERE AccountId = :accountId];
List<String> emails = new List<String>();
for (Contact c : contacts) {
emails.add(c.Email);
}
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(emails);
mail.setSubject('Important Update');
mail.setPlainTextBody('Please be informed of the following...');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
• Explanation: The email is sent to all contacts associated with a specific account.
Example:
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {'contact@example.com'});
mail.setSubject('Attached PDF');
mail.setPlainTextBody('Please find the attached PDF document.');
Blob pdfBlob = Blob.valueOf('PDF Content');
Messaging.EmailFileAttachment attachment = new Messaging.EmailFileAttachment();
attachment.setFileName('document.pdf');
attachment.setBody(pdfBlob);
mail.setFileAttachments(new Messaging.EmailFileAttachment[] { attachment });
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
• Explanation: This example demonstrates sending an email with a PDF file as an attachment.
Example:
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {'contact@example.com'});
mail.setSubject('Welcome!');
mail.setHtmlBody('<h1>Welcome to our service!</h1><p>We are glad to have you.</p>');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
• Explanation: The email body is set using HTML, allowing for more formatting options.
Example:
List<Messaging.SingleEmailMessage> mails = new
List<Messaging.SingleEmailMessage>();
List<Lead> leads = [SELECT Email FROM Lead WHERE Email != null];
for (Lead l : leads) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {l.Email});
mail.setSubject('Important Update');
mail.setPlainTextBody('Please review the latest updates.');
mails.add(mail);
}
Messaging.sendEmail(mails);
• Explanation: This approach sends individual emails to all leads, ensuring each email is personalized.
Example:
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {'contact@example.com'});
mail.setSenderDisplayName('Acme Support');
mail.setSubject('Support Inquiry');
mail.setPlainTextBody('Thank you for contacting Acme Support.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
• Explanation: The setSenderDisplayName method customizes the name that appears in the recipient's inbox.
public class AccountBatch implements Database.Batchable<SObject> {
public Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT Id, Name FROM Account');
}
public void execute(Database.BatchableContext BC, List<Account> scope)
{
for (Account acc : scope) {
// Perform processing
}
update scope;
}
public void finish(Database.BatchableContext BC) {
// Post-batch operations
}
}
• Explanation: Batch Apex is designed to process large volumes of records in chunks, allowing you to stay within governor limits by processing data in manageable batches.
AccountBatch batchJob = new AccountBatch();
String cronExp = '0 0 0 * * ?'; // At midnight every day
System.schedule('Daily Account Batch', cronExp, batchJob);
• Explanation: The System.schedule method allows you to schedule Batch Apex jobs using a cron expression.
public void finish(Database.BatchableContext BC) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {'admin@example.com'});
mail.setSubject('Batch Job Completed');
mail.setPlainTextBody('The batch job has finished processing.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
• Explanation: The finish method in Batch Apex is ideal for executing post-processing tasks, such as sending email notifications.
public class AccountBatch implements Database.Batchable<SObject>, Database.Stateful {
public Integer processedRecords = 0;
public void execute(Database.BatchableContext BC, List<Account> scope) {
processedRecords += scope.size();
update scope;
public void finish(Database.BatchableContext BC) {
System.debug('Total records processed: ' + processedRecords);
}
}
}
• Explanation: Implementing Database.Stateful allows you to maintain state across multiple execute method invocations, such as counting processed records.
Answer:
public void execute(Database.BatchableContext BC, List<Account> scope) {
for (Account acc : scope) {
try {
// Perform processing
update acc;
} catch (Exception e) {
System.debug('Error processing record: ' + acc.Id + ', Error: ' +
e.getMessage());
}
}
}
• Explanation: Using a try-catch block within the execute method allows you to handle errors at the record level, ensuring that the batch job continues processing other records.
public Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT Id, Name FROM Contact WHERE CreatedDate > LAST_YEAR');
}
• Explanation: Database.getQueryLocator returns a QueryLocator object that efficiently handles large query results by breaking them into smaller batches.
public void execute(Database.BatchableContext BC, List<Account> scope) {
List<Account> accountsToUpdate = new List<Account>();
for (Account acc : scope) {
acc.Name = 'Updated ' + acc.Name;
accountsToUpdate.add(acc);
}
update accountsToUpdate;
}
public void executeBatch() {
Database.executeBatch(new AccountBatch(), 10);
}
• Explanation: The second parameter in Database.executeBatch specifies the batch size, allowing you to process records in smaller chunks.
public class ProjectBatch implements Database.Batchable<SObject> {
public Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT Id, Name FROM Project__c WHERE
Status__c = \'In Progress\'');
}
public void execute(Database.BatchableContext BC, List<SObject> scope) {
List<Project__c> projects = (List<Project__c>)scope;
for (Project__c proj : projects) {
proj.Status__c = 'Completed';
}
update projects;
}
public void finish(Database.BatchableContext BC) {
// Post-processing actions
}
}
• Explanation: This Batch Apex job processes records from the Project__c custom object, updating the status of each project.
public class DailyJob implements Schedulable {
public void execute(SchedulableContext SC) {
// Your logic here
}
}
String cronExp = '0 0 2 * * ?'; // 2:00 AM daily
System.schedule('Daily Job', cronExp, new DailyJob());
• Explanation: The System.schedule method is used with a cron expression to schedule the DailyJob class to run every day at 2:00 AM.
public class WeeklyJob implements Schedulable {
public void execute(SchedulableContext SC) {
// Your logic here
}
}
String cronExp = '0 0 6 ? * MON'; // 6:00 AM every Monday
System.schedule('Weekly Job', cronExp, new WeeklyJob());
• Explanation: The cron expression 0 0 6 ? * MON is used to run the job every Monday at 6:00 AM.
public class MonthlyJob implements Schedulable {
public void execute(SchedulableContext SC) {
// Your logic here
}
}
String cronExp = '0 59 23 L * ?'; // 11:59 PM on the last day of each month
System.schedule('Monthly Job', cronExp, new MonthlyJob());
public class HourlyJob implements Schedulable {
public void execute(SchedulableContext SC) {
// Your logic here
}
}
String cronExp = '0 0 * * * ?'; // At the top of every hour
System.schedule('Hourly Job', cronExp, new HourlyJob());
• Explanation: The cron expression 0 0 * * * ? schedules the job to run at the start of every hour.
public class DynamicJob implements Schedulable {
public void execute(SchedulableContext SC) {
// Your logic here
}
}
Integer minutesFromNow = 30;
Datetime runTime = System.now().addMinutes(minutesFromNow);
String cronExp = runTime.format('s m H d M ? yyyy');
System.schedule('Dynamic Job', cronExp, new DynamicJob());
• Explanation: This solution calculates the future run time dynamically and converts it into a cron expression for scheduling.
public class FirstJob implements Schedulable {
public void execute(SchedulableContext SC) {
// Your logic here
System.schedule('Second Job', System.now().format('s m H d M ? yyyy'), new SecondJob());
}
}
public class SecondJob implements Schedulable {
public void execute(SchedulableContext SC) {
// Logic for second job
}
}
• Explanation: The second job is scheduled within the execute method of the first job, ensuring it runs immediately after the first job completes.
public class SafeJob implements Schedulable {
public void execute(SchedulableContext SC) {
if (!Lock__c.getInstance().isLocked()) {
Lock__c.getInstance().lock();
try {
// Your job logic here
} finally {
Lock__c.getInstance().unlock();
}
} else {
System.debug('Job already running.');
}
}
}
• Explanation: A custom locking mechanism is used to check whether the job is already running. If it is, the new instance does not start.
public class LimitedLifespanJob implements Schedulable {
public void execute(SchedulableContext SC) {
if (System.today() <= Date.today().addDays(7)) {
// Your job logic here
} else {
System.abortJob(SC.getTriggerId());
}
String cronExp = '0 0 2 * * ?'; // 2:00 AM daily
System.schedule('Limited Lifespan Job', cronExp, new LimitedLifespanJob());
• Explanation: The job checks the current date and aborts itself after 7 days.
public class ParametrizedJob implements Schedulable {
private String param;
public ParametrizedJob(String param) {
this.param = param;
}
public void execute(SchedulableContext SC) {
System.debug('Parameter: ' + param);
// Your logic here
}
}
String cronExp = '0 0 12 * * ?';
ParametrizedJob job = new ParametrizedJob('Parameter Value');
System.schedule('Parametrized Job', cronExp, job);
• Explanation: The job is scheduled with a parameter passed through its constructor, allowing for dynamic behavior.
CronTrigger ct = [SELECT Id FROM CronTrigger WHERE CronJobDetail.Name = 'Job to Unschedule' LIMIT 1];
System.abortJob(ct.Id);
• Explanation: The job is unscheduled using the System.abortJob method, which requires the job’s ID.
public class AccountHandler {
@future(callout=true)
public static void performCallout(Id accountId) {
Account acc = [SELECT Id, Name FROM Account WHERE Id = :accountId];
// Perform the callout logic here
}
}
• Explanation: The future method is marked with @future(callout=true) to allow a callout from within the method, ensuring the callout is processed asynchronously after the account update.
public class DataProcessor {
@future
public static void processLargeDataSet(List<Id> recordIds) {
List<SObject> records = [SELECT Id, Name FROM SObject WHERE Id IN :recordIds];
// Perform processing on the records
}
}
• Explanation: The future method processes a list of record IDs asynchronously, which is useful for handling large data volumes without hitting synchronous processing limits.
public class MixedDMLOperationHandler {
public void createUserAndUpdateRecord() {
User newUser = new User(Username = 'newuser@example.com', ...);
insert newUser;
updateRecordAsync();
}
@future
public static void updateRecordAsync() {
// Perform the record update here
}
}
• Explanation: The future method updateRecordAsync is used to perform the DML operation on a setup object asynchronously, avoiding the mixed DML error.
public class LongRunningOperation {
@future
public static void recalculateValues(List<Id> recordIds) {
for (Id recordId : recordIds) {
// Perform the long-running operation
}
}
}
• Explanation: The future method is ideal for executing operations that might take a long time to complete, ensuring they do not block the main transaction.
public class ExternalServiceHandler {
@future(callout=true)
public static void updateRecordsFromService(Id recordId) {
// Callout to the external service
// Update the record based on the response
}
}
• Explanation: The future method is used to make the callout and update records asynchronously, ensuring the callout does not delay the original transaction.
trigger AccountTrigger on Account (after update) {
List<Id> accountIds = new List<Id>();
for (Account acc : Trigger.new) {
accountIds.add(acc.Id);
}
AccountHandler.handleAccountUpdates(accountIds);
}
public class AccountHandler {
@future
public static void handleAccountUpdates(List<Id> accountIds) {
// Process the accounts asynchronously
}
}
public class EmailNotifier {
@future
public static void sendNotification(List<Id> recordIds) {
List<SObject> records = [SELECT Id, Name FROM SObject WHERE Id IN :recordIds];
// Send email notifications
}
}
• Explanation: The future method sends email notifications asynchronously, ensuring the main transaction is not delayed by email processing.
public class BatchProcessor {
@future
public static void processRecords(List<Id> recordIds) {
List<SObject> records = [SELECT Id, Name FROM SObject WHERE Id IN :recordIds];
// Perform processing on the records
}
}
• Explanation: Future methods can accept primitive data types or collections of primitive types as parameters, allowing you to pass necessary data for asynchronous processing.
public class ExceptionHandler {
@future
public static void processWithExceptionHandling() {
try {
// Perform operations that might throw an exception
} catch (Exception e) {
System.debug('Exception: ' + e.getMessage());
}
}
}
• Explanation: A try-catch block is used within the future method to handle exceptions and prevent the asynchronous process from failing silently.
public class DataIntegration {
@future(callout=true)
public static void sendDataToExternalSystem(Id recordId) {
// Prepare data and perform callout to the external system
}
}
public class ProcessLargeDataSet implements Queueable {
public void execute(QueueableContext context) {
List<Account> accounts = [SELECT Id, Name FROM Account WHERE Industry = 'Technology'];
for (Account acc : accounts) {
acc.Name = acc.Name + ' - Processed';
}
update accounts;
}
}
• Explanation: Queueable Apex is ideal for handling large data sets asynchronously, allowing you to process records without hitting synchronous governor limits.
public class FirstJob implements Queueable {
public void execute(QueueableContext context) {
// Processing logic for the first job
System.enqueueJob(new SecondJob());
}
}
public class SecondJob implements Queueable {
public void execute(QueueableContext context) {
// Processing logic for the second job
}
}
public class CalloutJob implements Queueable, Database.AllowsCallouts {
public void execute(QueueableContext context) {
HttpRequest req = new HttpRequest();
req.setEndpoint('https://example.com/api');
req.setMethod(‘GET');
HttpResponse res = new Http().send(req);
// Process the response
}
}
• Explanation: Implementing the Database.AllowsCallouts interface in Queueable Apex allows you to make HTTP callouts asynchronously.
public class ProcessRecordsJob implements Queueable {
private List<Account> accountsToProcess;
public ProcessRecordsJob(List<Account> accounts) {
this.accountsToProcess = accounts;
}
public void execute(QueueableContext context) {
for (Account acc : accountsToProcess) {
acc.Name = acc.Name + ' - Processed';
}
update accountsToProcess;
}
}
public class StatefulQueueableJob implements Queueable, Database.Stateful {
public Integer processedCount = 0;
public void execute(QueueableContext context) {
// Process records and update processedCount
processedCount += 10;
System.debug('Processed so far: ' + processedCount);
}
}
AsyncApexJob job = [SELECT Id FROM AsyncApexJob WHERE JobType = 'Queueable' AND Status = 'Holding' ORDER BY CreatedDate DESC LIMIT 1];
System.moveToStartOfQueue(job.Id);
public class ErrorHandlingJob implements Queueable {
public void execute(QueueableContext context) {
try {
// Perform processing
} catch (Exception e) {
System.debug('Error: ' + e.getMessage());
// Log the error or handle it accordingly
}
}
}
public class FirstJob implements Queueable {
public void execute(QueueableContext context) {
// Processing logic for the first job
System.enqueueJob(new SecondJob());
}
}
public class SecondJob implements Queueable {
public void execute(QueueableContext context) {
// Processing logic for the second job
System.enqueueJob(new ThirdJob());
}
}
public class ScheduledJob implements Schedulable {
public void execute(SchedulableContext SC) {
System.enqueueJob(new ProcessRecordsJob());
}
}
String cronExp = '0 0 12 * * ?'; // Run at 12:00 PM every day
System.schedule('Daily Queueable Job', cronExp, new ScheduledJob());
List<AsyncApexJob> jobs = [SELECT Id, Status, CreatedDate FROM AsyncApexJob WHERE JobType = 'Queueable'];
for (AsyncApexJob job : jobs) {
System.debug('Job ID: ' + job.Id + ', Status: ' + job.Status);
}
• Explanation: By querying the AsyncApexJob object, you can monitor the status of Queueable jobs, track their progress, and manage them within the Flex Queue.
trigger PreventDuplicateContacts on Contact (before insert) {
Set<String> emailSet = new Set<String>();
for (Contact con : Trigger.new) {
if (con.Email != null) {
emailSet.add(con.Email);
}
}
List<Contact> existingContacts = [SELECT Id, Email FROM Contact WHERE Email IN :emailSet];
for (Contact con : Trigger.new) {
if (existingContacts.contains(con.Email)) {
con.addError('A contact with this email already exists.');
}
}
}
Using Trigger Handler Class :
Trigger:
trigger PreventDuplicateContacts on Contact (before insert) {
ContactTriggerHandler.preventDuplicates(Trigger.new);
}
Handler Class:
public class ContactTriggerHandler {
public static void preventDuplicates(List<Contact> newContacts) {
Set<String> emailSet = new Set<String>();
for (Contact con : newContacts) {
if (con.Email != null) {
emailSet.add(con.Email);
}
}
List<Contact> existingContacts = [SELECT Id, Email FROM Contact WHERE Email IN :emailSet];
for (Contact con : newContacts) {
if (existingContacts.contains(con.Email)) {
con.addError('A contact with this email already exists.');
}
}
}
}
trigger UpdateOpportunitiesOnAccountChange on Account (after update) {
List<Opportunity> oppsToUpdate = new List<Opportunity>();
for (Account acc : Trigger.new) {
Account oldAcc = Trigger.oldMap.get(acc.Id);
if (acc.Industry != oldAcc.Industry) {
oppsToUpdate.addAll([SELECT Id FROM Opportunity WHERE AccountId = :acc.Id]);
}
for (Opportunity opp : oppsToUpdate) {
opp.Description = 'Updated due to Account industry change';
}
}
update oppsToUpdate;
}
Using Trigger Handler Class :
Trigger:
trigger UpdateOpportunitiesOnAccountChange on Account (after update) {
AccountTriggerHandler.updateOpportunitiesOnIndustryChange(Trigger.new, Trigger.oldMap);
}
Handler Class:
public class AccountTriggerHandler {
public static void updateOpportunitiesOnIndustryChange(List<Account>
newAccounts, Map<Id, Account> oldAccountMap) {
List<Opportunity> oppsToUpdate = new List<Opportunity>();
for (Account acc : newAccounts) {
Account oldAcc = oldAccountMap.get(acc.Id);
if (acc.Industry != oldAcc.Industry) {
oppsToUpdate.addAll([SELECT Id FROM Opportunity WHERE AccountId = :acc.Id]);
}
}
}
}
for (Opportunity opp : oppsToUpdate) {
opp.Description = 'Updated due to Account industry change';
if (!oppsToUpdate.isEmpty()) {
update oppsToUpdate;
}
}
trigger CreateCaseOnContactInsert on Contact (after insert) {
List<Case> casesToCreate = new List<Case>();
for (Contact con : Trigger.new) {
Case newCase = new Case(
ContactId = con.Id,
Subject = 'New Case for ' + con.LastName
);
casesToCreate.add(newCase);
}
insert casesToCreate;
}
Using Trigger Handler Class :
Trigger:
trigger CreateCaseOnContactInsert on Contact (after insert) {
ContactTriggerHandler.createCasesForNewContacts(Trigger.new);
}
Handler Class:
public class ContactTriggerHandler {
public static void createCasesForNewContacts(List<Contact> newContacts) {
List<Case> casesToCreate = new List<Case>();
for (Contact con : newContacts) {
Case newCase = new Case(
ContactId = con.Id,
Subject = 'New Case for ' + con.LastName
);
casesToCreate.add(newCase);
if (!casesToCreate.isEmpty()) {
insert casesToCreate;
}
}
}
}
trigger ValidateOpportunityCloseDate on Opportunity (before insert, before update)
{
for (Opportunity opp : Trigger.new) {
if (opp.CloseDate < Date.today()) {
opp.addError('Close Date cannot be in the past.');
}
}
}
• Explanation: The trigger validates the close date of an opportunity and prevents the record
from being saved if the close date is in the past.
Using Trigger Handler Class :
Trigger:
trigger ValidateOpportunityCloseDate on Opportunity (before insert, before update) {
OpportunityTriggerHandler.validateCloseDate(Trigger.new);
}
Handler Class:
public class OpportunityTriggerHandler {
public static void validateCloseDate(List<Opportunity> opportunities) {
for (Opportunity opp : opportunities) {
if (opp.CloseDate < Date.today()) {
opp.addError('Close Date cannot be in the past.');
}
}
}
}
Using Trigger Handler Class :
Trigger:
trigger ValidateOpportunityCloseDate on Opportunity (before insert, before update) {
OpportunityTriggerHandler.validateCloseDate(Trigger.new);
}
Handler Class:
public class OpportunityTriggerHandler {
public static void validateCloseDate(List<Opportunity> opportunities) {
for (Opportunity opp : opportunities) {
if (opp.CloseDate < Date.today()) {
opp.addError('Close Date cannot be in the past.');
}
}
}
}
trigger RollupOrderCount on Order__c (after insert, after delete, after undelete)
{
Set<Id> accountIds = new Set<Id>();
for (Order__c order : Trigger.isDelete ? Trigger.old : Trigger.new) {
accountIds.add(order.Account__c);
}
Map<Id, Account> accountsToUpdate = new Map<Id, Account>([SELECT Id, (SELECT Id FROM Orders__r) FROM Account WHERE Id IN :accountIds]);
for (Account acc : accountsToUpdate.values()) {
acc.Order_Count__c = acc.Orders__r.size();
}
update accountsToUpdate.values();
}
Using Trigger Handler Class :
Trigger:
trigger RollupOrderCount on Order__c (after insert, after delete, after undelete) {
OrderTriggerHandler.updateOrderCount(Trigger.new, Trigger.old, Trigger.isDelete);
}
Handler Class:
public class OrderTriggerHandler {
public static void updateOrderCount(List<Order__c> newOrders, List<Order__c> oldOrders, Boolean isDelete) {
Set<Id> accountIds = new Set<Id>();
for (Order__c order : isDelete ? oldOrders : newOrders) {
accountIds.add(order.Account__c);
}
Map<Id, Account> accountsToUpdate = new Map<Id, Account>([SELECT Id, (SELECT Id FROM Orders__r) FROM Account WHERE Id IN :accountIds]);
for (Account acc : accountsToUpdate.values()) {
acc.Order_Count__c = acc.Orders__r.size();
}
if (!accountsToUpdate.isEmpty()) {
update accountsToUpdate.values();
}
}
}
trigger LeadTrigger on Lead (before insert, before update) {
for (Lead lead : Trigger.new) {
if (lead.Status == 'Qualified' && lead.Industry == null) {
lead.addError('Industry must be specified for Qualified leads.');
}
}
}
Using Trigger Handler Class :
Trigger:
trigger LeadTrigger on Lead (before insert, before update) {
LeadTriggerHandler.validateQualifiedLead(Trigger.new);
}
Handler Class:
public class LeadTriggerHandler {
public static void validateQualifiedLead(List<Lead> leads) {
for (Lead lead : leads) {
if (lead.Status == 'Qualified' && lead.Industry == null) {
lead.addError('Industry must be specified for Qualified leads.');
}
}
}
}
trigger PreventAccountDeletion on Account (before delete) {
for (Account acc : Trigger.old) {
Integer oppCount = [SELECT COUNT() FROM Opportunity WHERE AccountId = :acc.Id];
if (oppCount > 0) {
acc.addError('Cannot delete account with related opportunities.');
}
}
}
Using Trigger Handler Class :
Trigger:
trigger PreventAccountDeletion on Account (before delete) {
AccountTriggerHandler.preventAccountDeletionWithOpportunities(Trigger.old);
}
Handler Class:
public class AccountTriggerHandler {
public static void preventAccountDeletionWithOpportunities(List<Account> oldAccounts)
{
for (Account acc : oldAccounts) {
Integer oppCount = [SELECT COUNT() FROM Opportunity WHERE AccountId = :acc.Id];
if (oppCount > 0) {
acc.addError('Cannot delete account with related opportunities.');
}
}
}
}
trigger UpdateLastContactedDate on Task (after update) {
Map<Id, Contact> contactsToUpdate = new Map<Id, Contact>();
for (Task task : Trigger.new) {
if (task.Status == 'Completed' && task.WhoId != null && task.Who.Type == 'Contact') {
contactsToUpdate.put(task.WhoId, new Contact(Id = task.WhoId,
Last_Contacted_Date__c = task.ActivityDate));
}
}
update contactsToUpdate.values();
}
Using Trigger Handler Class :
Trigger:
trigger UpdateLastContactedDate on Task (after update) {
TaskTriggerHandler.updateLastContactedDate(Trigger.new);
}
Handler Class:
public class TaskTriggerHandler {
public static void updateLastContactedDate(List<Task> tasks) {
Map<Id, Contact> contactsToUpdate = new Map<Id, Contact>();
for (Task task : tasks) {
if (task.Status == 'Completed' && task.WhoId != null && task.Who.Type == 'Contact') {
contactsToUpdate.put(task.WhoId, new Contact(Id = task.WhoId,
Last_Contacted_Date__c = task.ActivityDate));
}
}
if (!contactsToUpdate.isEmpty()) {
update contactsToUpdate.values();
}
}
}
public class TriggerHelper {
public static Boolean isTriggerExecuted = false;
}
trigger OpportunityTrigger on Opportunity (before update) {
if (TriggerHelper.isTriggerExecuted) return;
TriggerHelper.isTriggerExecuted = true;
for (Opportunity opp : Trigger.new) {
// Perform logic
}
}
• Explanation: A static Boolean variable is used to track whether the trigger has already run, preventing recursive execution.
Using Trigger Handler Class :
Trigger:
trigger OpportunityTrigger on Opportunity (before update) {
if (TriggerHelper.isTriggerExecuted) return;
TriggerHelper.isTriggerExecuted = true;
OpportunityTriggerHandler.handleOpportunityUpdate(Trigger.new);
}
Helper Class:
public class TriggerHelper {
public static Boolean isTriggerExecuted = false;
}
Handler Class:
public class OpportunityTriggerHandler {
public static void handleOpportunityUpdate(List<Opportunity> opportunities) {
// Implement your logic here
}
}
trigger UpdateAccountOnOpportunityClose on Opportunity (after update) {
Map<Id, Account> accountsToUpdate = new Map<Id, Account>();
for (Opportunity opp : Trigger.new) {
if (opp.StageName == 'Closed Won') {
Account acc = accountsToUpdate.get(opp.AccountId);
if (acc == null) {
acc = new Account(Id = opp.AccountId);
accountsToUpdate.put(acc.Id, acc);
}
acc.Last_Opportunity_Closed_Date__c = opp.CloseDate;
}
}
update accountsToUpdate.values();
}
Using Trigger Handler Class :
Trigger:
trigger UpdateAccountOnOpportunityClose on Opportunity (after update) {
OpportunityTriggerHandler.updateAccountOnOpportunityClose(Trigger.new);
}
Handler Class:
public class OpportunityTriggerHandler {
public static void updateAccountOnOpportunityClose(List<Opportunity> opportunities) {
Map<Id, Account> accountsToUpdate = new Map<Id, Account>();
for (Opportunity opp : opportunities) {
if (opp.StageName == 'Closed Won') {
Account acc = accountsToUpdate.get(opp.AccountId);
if (acc == null) {
acc = new Account(Id = opp.AccountId);
accountsToUpdate.put(acc.Id, acc);
}
acc.Last_Opportunity_Closed_Date__c = opp.CloseDate;
}
if (!accountsToUpdate.isEmpty()) {
update accountsToUpdate.values();
}
}
}
}
Test Class:
@isTest
public class ContactTriggerHandlerTest {
@isTest
static void testPreventDuplicateContacts() {
Contact con1 = new Contact(FirstName = 'John', LastName = 'Doe', Email = 'john.doe@example.com');
Contact con2 = new Contact(FirstName = 'Jane', LastName = 'Doe', Email = 'john.doe@example.com');
insert con1;
Test.startTest();
try {
insert con2;
System.assert(false, 'Expected exception not thrown.');
} catch (DmlException e) {
System.assert(e.getMessage().contains('A contact with this email already exists.'));
}
Test.stopTest();
}
}
Test Class:
@isTest
public class AccountTriggerHandlerTest {
@isTest
static void testUpdateOpportunitiesOnIndustryChange() {
Account acc = new Account(Name = 'Test Account', Industry = 'Technology');
insert acc;
Opportunity opp = new Opportunity(Name = 'Test Opportunity', AccountId =
acc.Id, StageName = 'Prospecting', CloseDate = Date.today().addMonths(1));
insert opp;
acc.Industry = 'Healthcare';
Test.startTest();
update acc;
Test.stopTest();
Opportunity updatedOpp = [SELECT Id, Description FROM Opportunity WHERE Id
= :opp.Id];
System.assertEquals('Updated due to Account industry change',
updatedOpp.Description);
}
}
• Explanation: The test class updates an account’s industry and verifies that the related
opportunity’s description is updated as expected by the trigger.
Test Class:
@isTest
public class ContactTriggerHandlerTest {
@isTest
static void testCreateCaseOnContactInsert() {
Contact con = new Contact(FirstName = 'John', LastName = 'Doe'); Test.startTest();
insert con;
Test.stopTest();
Case createdCase = [SELECT Id, Subject FROM Case WHERE ContactId = :con.Id];
System.assertEquals('New Case for Doe', createdCase.Subject);
}
}
Test Class:
@isTest
public class OpportunityTriggerHandlerTest {
@isTest
static void testValidateCloseDate() {
Opportunity opp = new Opportunity(Name = 'Test Opportunity', StageName = 'Prospecting', CloseDate = Date.today().addDays(-1));
Test.startTest();
try {
insert opp;
System.assert(false, 'Expected exception not thrown.');
} catch (DmlException e) {
System.assert(e.getMessage().contains('Close Date cannot be in the past.'));
}
Test.stopTest();
}
}
Test Class:
@isTest
public class OrderTriggerHandlerTest {
@isTest
static void testRollupOrderCount() {
Account acc = new Account(Name = 'Test Account');
insert acc;
Order__c order1 = new Order__c(Account__c = acc.Id);
Order__c order2 = new Order__c(Account__c = acc.Id);
insert new List<Order__c>{order1, order2};
Test.startTest();
OrderTriggerHandler.updateOrderCount(Trigger.new, null, false);
Test.stopTest();
Account updatedAccount = [SELECT Order_Count__c FROM Account WHERE Id = :acc.Id];
System.assertEquals(2, updatedAccount.Order_Count__c);
Test Class:
@isTest
public class LeadTriggerHandlerTest {
@isTest
static void testLeadTrigger() {
Lead lead = new Lead(FirstName = 'John', LastName = 'Doe', Company = 'Test Company', Status = 'Qualified');
Test.startTest();
try {
insert lead;
System.assert(false, 'Expected exception not thrown.');
} catch (DmlException e) {
System.assert(e.getMessage().contains('Industry must be specified for Qualified leads.'));
}
lead.Industry = 'Technology';
update lead;
Test.stopTest();
Lead updatedLead = [SELECT Industry FROM Lead WHERE Id = :lead.Id];
System.assertEquals('Technology', updatedLead.Industry);
}
}
Test Class:
@isTest
public class AccountTriggerHandlerTest {
@isTest
static void testPreventAccountDeletion() {
Account acc = new Account(Name = 'Test Account');
insert acc;
Opportunity opp = new Opportunity(Name = 'Test Opportunity',
AccountId = acc.Id, StageName = 'Prospecting', CloseDate = Date.today().addMonths(1));
insert opp;
Test.startTest();
try {
delete acc;
System.assert(false, 'Expected exception not thrown.');
} catch (DmlException e) {
System.assert(e.getMessage().contains('Cannot delete account with related opportunities.'));
}
Test.stopTest();
}
}
Test Class:
@isTest
public class TaskTriggerHandlerTest {
@isTest
static void testUpdateLastContactedDate() {
Contact con = new Contact(FirstName = 'John', LastName = 'Doe');
insert con;
Task task = new Task(WhoId = con.Id, Status = 'Not Started', ActivityDate = Date.today());
insert task;
task.Status = 'Completed';
Test.startTest();
update task;
Test.stopTest();
Contact updatedContact = [SELECT Last_Contacted_Date__c FROM Contact WHERE Id = :con.Id];
System.assertEquals(Date.today(), updatedContact.Last_Contacted_Date__c);
}
}
Test Class:
@isTest
public class OpportunityTriggerHandlerTest {
@isTest
static void testTriggerRecursionPrevention() {
// Create an opportunity
Opportunity opp = new Opportunity(Name = 'Test Opportunity', StageName = 'Prospecting', CloseDate = Date.today().addMonths(1));
insert opp;
// Update the opportunity to simulate trigger execution
opp.StageName = 'Qualification';
Test.startTest();
update opp;
Test.stopTest();
// Since the trigger is designed to prevent recursion,
// we would check for some indicator in the logic (e.g., a static variable or a field update)
// Here, we assume that the trigger only modifies the record once
Opportunity updatedOpp = [SELECT StageName FROM Opportunity WHERE Id = :opp.Id];
System.assertEquals('Qualification', updatedOpp.StageName); // Assuming no further change by trigger recursion
}
}
Test Class:
@isTest
public class OpportunityTriggerHandlerTest {
@isTest
static void testUpdateAccountOnOpportunityClose() {
// Create an account
Account acc = new Account(Name = 'Test Account');
insert acc;
// Create an opportunity related to the account
Opportunity opp = new Opportunity(Name = 'Test Opportunity', AccountId =
acc.Id, StageName = 'Prospecting', CloseDate = Date.today().addMonths(1));
insert opp;
// Update the opportunity to 'Closed Won'
opp.StageName = 'Closed Won';
opp.CloseDate = Date.today();
Test.startTest();
update opp;
Test.stopTest();
// Verify the Account's Last_Opportunity_Closed_Date__c field was updated
Account updatedAccount = [SELECT Last_Opportunity_Closed_Date__c FROM
Account WHERE Id = :acc.Id];
System.assertEquals(Date.today(),
updatedAccount.Last_Opportunity_Closed_Date__c);
}
}