Salesforce Interview Questions and Answers
A collection of Salesforce interview questions and answers, including Apex, SOQL, triggers, security, batch Apex, and Lightning Web Components.
Question 1. What are the different types of relationships we have in Salesforce?
In Salesforce we have 6 different types of relationships:
Lookup – It is a loosely coupled relationship between two objects. Where objects can be connected as Many to One or One to Many.
Master Detail – It is a tightly coupled relationship between two objects. It also can be Many to one and One to many. tightly coupled means the Child record cannot exist without the Parent and If we delete the Parent then the child also gets deleted.
Many-Many – It is a type of relationship where an object can have multiple children of another object and vice versa. Suppose we have obj A and obj B So now A can have multiple B records associated with and B can also have multiple A’s associated with it. To establish this kind of relationship we took a junction object which acts as a child for both objects A and B.
Self – It is a relationship where obj is connected to itself. For example, we have an Account object which has a self-lookup. Where an account can act as a Parent record and can have child accounts associated with it.
External – This relationship is implemented through the use of lookup where an external object is related to a Salesforce object.
Hierarchal – It is a unique relationship in salesforce which applies to the User object. It displays the parent-child relationship within a single object. It basically enables users to select another user as their manager.
Question 2. How can we handle record-level security?
In Salesforce we can handle record-level security in the following different ways:
OWD – It’s the baseline level of security. Here we define the default level of access that a user gets on records they don’t own. We have a different option which defines which level of access would be given: Private, Public Read-Only, Public Read/Write, Public Read/Write/Transfer.
Role hierarchy – In this option user gets access to the record owned by other users in roles below them. As this option is used to open up the security given by OWD it extends the access when the Sharing Setting is set to not more restrictive than Public Read/Write. So if OWD is set to Public Read/Write so there is no need to give access from Role Hierarchy.
Sharing Rules – They are used to give access to records to the user based on ownership or some criteria. It opens up access compared to Role Hierarchy. So while creating we have two options: Based on the record owner and Based on criteria. For example: if we have to provide access to some user if Opportunity moves to Closed Won then we can achieve this scenario by use of Sharing Rules.
Manual Sharing – We use this when we want to share access to individual records with some users, groups, etc. To provide access we can just simply go to the record we want to share and click on the Sharing option available on the Record Page then Select whom we want to share and what access we want to provide.
Question 3. Suppose I have a scenario where I have one master detail relationship between A(master) and B object. Currently, the OWD of A is public read-only and now I have changed the relationship to lookup. What will be the OWD now of B object?
In the master-detail relationship, the child sharing setting will be controlled by a parent but when we update the data type to lookup, the child object (B) OWD will be updated to Public Read/Write.
Question 4. How can we call Apex in Flow?
If we want to call out Apex in flow then we have to use Invocable method annotation in our apex class. Basically, by annotating with this, we are making our class accessible to the salesforce declarative tools.
Below is the syntax:
public class DemoClass {
@InvocableMethod(label='Test' description='Test' category='Test')
public static void demoMethod() {
}
}Question 5. What are the different types of trigger and context variables we have in Salesforce?
In Salesforce we have two types of triggers which are before and after which define whether the trigger executes before or after the record gets saved to the database. Following are the different types of context variables we have in Trigger:
isInsert
isUpdate
isDelete
isBefore
isAfter
New
Old
oldMap
newMap
isExecuting
isUndelete
operationType
size
Question 6. What is recursion in Trigger and how can we prevent it?
Recursion occurs when the trigger invokes itself in a loop and eventually hits the governor’s limit due to repeated execution and iteration. We can also encounter the error “Maximum trigger depth exceeded” due to multiple executions because the stack depth limit in Salesforce is 16.
For Example: If a trigger is firing on an Account’s update and in that trigger logic we are updating those Accounts then it will lead to recursion due to multiple executions.
Avoiding recursion is very important in Salesforce to ensure stability and efficiency. We have different methods to avoid recursion in trigger
Following are the ways by which we can prevent recursion in trigger:
Static Boolean variable – We will use the boolean variable make it default true, and check the value if true, will enter it into the transaction and make it false afterwards.
Static Set – In this process we will store the processed ID and check if the ID is contained in the Set or not.
Static Map – Here, we will create a Map of String and Set of Id (Map<String, Set<Id>>) to store the processed Id with their event.
Static Old Map – We will use the old map to compare the values before executing.
Question 7. Write a trigger to calculate the total contact that the Account has and also include all applicable context variables.
To achieve this scenario we have two ways. Firstly we create our trigger on Contact as shown below
trigger ContactTrigger on Contact (after update, before update, after insert, before insert, after delete, before delete, after undelete) {
if(Trigger.isAfter) {
if(Trigger.isInsert || Trigger.isUpdate || Trigger.isDelete || Trigger.isUndelete) {
ContactTriggerHandler.updateContactCount(Trigger.newMap, Trigger.oldMap);
}
}
}
Here we are using After because we are performing operation on a related object. This scenario will be applicable to Insert, Update, Delete and Undelete. It is better to have trigger logic less which means it is a best practice to write any logic in the trigger so that’s why we have used a helper class here as “ContactTriggerHandler”. Below is the code for this helper.
public class ContactTriggerHandler {
public static void updateContactCount(Map<Id,Contact> newMapContactById, Map<Id,Contact> oldMapContactById) {
Set<Id>accountIds = new Set<Id>();
List<Account>accountsToUpdate = new List<Account>();
if(newMapContactById != null) {
for(Contact con: newMapContactById.values()) {
if(con.AccountId != null) {
if(oldMapContactById != null && oldMapContactById.size() > 0) {
Contact oldContact = oldMapContactById.get(con.Id);
if(oldContact.AccountId != con.AccountId) {
accountIds.add(oldContact.AccountId);
}}
accountIds.add(con.AccountId);
}}
}
if(oldMapContactById != null) {
for(Contact con: oldMapContactById.values()) {
accountIds.add(con.AccountId);
}
}
List<AggregateResult> aggList = [SELECT Count(Id) countId, AccountId FROM Contact
WHERE AccountId IN : accountIds GROUP By AccountId ];
for(AggregateResult agg : aggList) {
Account acc = new Account();
acc.Id = (Id)agg.get('AccountId');
acc.No_of_Contact__c = (Double)agg.get('countId');
accountsToUpdate.add(acc);
}
try {
if(accountsToUpdate != null && accountsToUpdate.size() > 0) {
update accountsToUpdate;
}
}
catch(Exception e) {
System.debug('Error occured while updating Account '+ e.getMessage());
}
}
}
Above the is code to update the Account with the number of contacts. Here we have created the custom field to update the count No_of_Contact__c. We have utilised Aggregate SOQL here to calculate the count.
Below is another way of updating the Contact count in the Account without using Aggregate SOQL.
for(Account acc : [SELECT Id,No_of_Contact__c, (SELECT Id FROM Contacts) FROM Account WHERE Id IN : accountIds]) {
acc.No_of_Contact__c = acc.contacts.size();
accountsToUpdate.add(acc);
}Question 8. Suppose I have a scenario where I want to restrict the user from updating the Account record multiple times if the record is already updated within that 1 hour. Write a trigger for this scenario
Here we have to apply validation to restrict users to update accounts within the same hour. So we will be using before type here.
trigger AccountTrigger on Account (after update, before update, after insert, before insert, after delete, before delete, after undelete) {
if(Trigger.isBefore && Trigger.isUpdate)
AccountTriggerHandler.restrictAccountUpdate(Trigger.oldMap, Trigger.newMap);
}
public class AccountTriggerHandler {
public static void restrictAccountUpdate(Map<Id,Account>oldAccountMap, Map<Id,Account>newAccountMap) {
if(newAccountMap != null) {
for(Account acc: newAccountMap.values()) {
if(oldAccountMap != null) {
Account oldRecords = oldAccountMap.get(acc.Id);
if(oldRecords.LastModifiedDate.addHours(1) > System.now()) {
acc.addError('You cannot update account within 1 hours');
} } } } }
}Question 9. What is with sharing and without sharing in Apex?
We can use this in class to determine whether sharing rules should be enforced or not.
With Sharing – When we want to run our apex class in respective of the Sharing rules of the current user then we use it. Below is the syntax of how we can apply it.
public with sharing class demoClass {
// Code here
}
Without Sharing – When we don’t want to run our apex class in respective of the Sharing rules of the current user’s then we use it. Below is the syntax of how we can apply it. It is a best practice to always use the class in with sharing until and unless there is a specific requirement to use without sharing.
public without sharing class demoClass {
// Code here
}
Also, it only applies to share and does not enforce the field and object level security. If we want to enforce those we have to explicitly apply it. For example: If the user does not have access to obj A so even though the class is running without sharing user will not get access to obj A.
Question 10. In continuation of the above question, does the apex trigger run with sharing or without sharing?
Apex triggers can’t have an explicit sharing declaration and run as without sharing.
Question 11. I have two Apex classes A and B. A is OuterClass which is called B so that will be an InnerClass. A is running in with sharing context and B is running without sharing context. Now B has a method inside it, So in which context will that method be running?
Class B’s method will run without sharing context and will not depend on the outer class. Inner classes do not inherit the sharing setting from their container class.
Question 12. What is row cause in sharing?
Row cause in sharing in Salesforce used in Apex sharing. It basically stores the reason why a particular record is being shared with a user or a group.
Question 13. Write an SOQL to fetch all Accounts which is not associated with any contacts
To execute this SOQL we will use the NOT operator in SOQL. Below is the SOQL we used. Here we have used NOT IN and then we have also used another query which basically gives the AccountId from Contact. So it will filter out the Account whose ID is not there in any contacts.
SELECT Id, Name FROM Account WHERE Id NOT IN (SELECT AccountId FROM Contact)Question 14. I have a scenario where I want to fetch the Account with second second-highest Annual Revenue.
To implement this scenario we can OFFSET and LIMIT available in SOQL. OFFSET basically removes the n record from the list. LIMIT gives us only n record.
So to show you I have also executed another SOQL which is ordered by Annual Revenue in Descending order and we can see “Express Logistics and Transport” coming as the second highest.
Now to just fetch the second highest only we can use the below SOQL.
SELECT Id, Name, AnnualRevenue FROM Account WHERE AnnualRevenue != null ORDER BY AnnualRevenue DESC LIMIT 1 OFFSET 1
Below is the output:
Question 15. How can we enable field security while implementing our SOQL?
To apply field-level security we can use WITH USER_MODE or WITH SYSTEM_MODE. In User mode, the security will be respected of that current user but with System mode, it will not apply the user’s security and will run in the System context. Below is the sample code of how can we implement it.
List<Account> acc = [SELECT Id FROM Account WITH USER_MODE];Question 16. Business Scenario
I have a field called Rating on Account which is having 3 picklist values: Hot, Warm, and Cold. I want to write a SOQL query to fetch the counts of each value. Like I want to know how many records have a Rating Hot value in the Rating field and so on for each value.
Here we can use the aggregate SOQL like below.
SELECT Count(Id), Rating FROM Account WHERE Rating != null GROUP BY RatingQuestion 17. How can we fetch the current user’s ID in LWC without using Apex?
To fetch the current user’s ID in LWC we can use the salesforce module and we can import the ID from it. Below is the sample JS
import { LightningElement } from 'lwc';
import Id from '@salesforce/user/Id';
export default class GetUserIdComp extends LightningElement {
userId = Id;
}Question 18. Suppose we have a field on Account as Active of type picklist and has 2 values: Yes, No. While creating the value we can provide any value amongst this picklist but once we update it to Yes, It can’t be moved to No. How can we implement this scenario?
To implement this scenario we make use of the before update trigger. Below is the helper class logic we can use
public class AccountTriggerHandler {
public static void restrictAccountUpdate(Map<Id,Account>oldAccountMap, Map<Id,Account>newAccountMap) {
for (Account acc : newAccountMap.values()) {
Account oldAcc = oldAccountMap.get(acc.Id);
if (oldAcc.Active__c == 'Yes' && acc.Active__c != 'Yes') {
acc.addError('Account cannot be deactivated once active);}
}
} }Question 19. Business Scenario
Suppose I have a sharing rule by which User A is getting access to certain records as that user is part of a certain group which is mentioned in the sharing rule. Now I want to limit access to a few records that have matching criteria from User A. How can I implement this scenario?
To implement this scenario we can make use of Restriction Rules. These are available on custom objects, external objects, contracts, events, tasks, time sheets, and timesheet entries. They basically apply a filter to the records shared via OWD or another share mechanism. We can have up to 2 restriction rules per object.
Question 20. What is mixed DML error and when do we encounter it??
We encounter this error whenever we are performing DML operations on the Setup and Non-Setup objects in a single transaction due to which sharing is getting recalculated then only we face this error. Let’s take a look at the below code to understand it clearly.
public static void mixedDMLDemo() {
Account a = new Account(Name='Test Account');
insert a;
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='CEO'];
User usr = new User(alias = 'testGeek', email='test@geek.com',
emailencodingkey='UTF-8', lastname='Geek',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='test@geek.com');
insert usr;
}
Here, we are inserting Account and User both in a single transaction and we are assigning user-role to that user due to which sharing is calculated as a result mixed DML will be introduced.
Question 21. What are the ways to avoid mixed DML errors?
To avoid this error we need to convert this process from synchronous to asynchronous. The possible way is to make it a Future Method. It will separate the transaction which help us to avoid this error.
Question 22. What is the default and maximum size of the batch?
The default is 200 and the maximum size is 2000.
Question 23. Can we call the future from the batch?
No, we cannot call future methods from batch apex. As they operate differently. Mixing these can lead to unexpected behaviour.
Question 24. Business Scenario
Suppose I am running a batch to update the object record. Now client wants when the batch finishes running, they should get the mail with the count of how many records updated successfully and how many have failed. How can we implement this scenario
We can implement this scenario by using a Database.Stateful interface. By using this our instance variable will maintain the state across multiple batches. Normally, when a batch job runs (without implementing Database.Stateful ) the instance variable gets reset between batch executions. Below is the code to implement
global class MyBatchClass implements Database.Batchable<sObject>,Database.Stateful {
// Define variables to store success and failure counts
// to store the count of success records
global Integer successCount = 0;
// to store the count of failure records
global Integer failureCount = 0;
global Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator([SELECT Id, Name FROM Object__c]);
}
global void execute(Database.BatchableContext bc, List<sObject> scope) {
// Perform callouts and process records
for (Object__c obj: scope) {
//execute logic
try {
// Increment success count
successCount++;
} catch (Exception e) {
// Handle records failure
failureCount++;
}}
}
global void finish(Database.BatchableContext bc) {
// Send email with success and failure counts
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {'user@example.com'};
mail.setToAddresses(toAddresses);
mail.setSubject('Batch Job Completion Report');
mail.setPlainTextBody('The batch job has completed.\\n\\nTotal Success Count: ' + successCount + '\\nTotal Failure Count: ' + failureCount);
// Send email
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}}Question 25. Business Scenario
I have an LWC component that takes multiple inputs from the user for the Account record and has a button which when the user clicks it, calls the apex method which handles the update. But while clicking the button user is facing below Limit Exception below. What could be the possible reason?
Below is the LWC and Apex running behind
Here in the code we can see that we are calling our apex method imperatively but we use the cacheable = true in the annotation with @AuraEnabled. So we have to use only @AuraEnabled with the imperative call because it doesn’t use the browser cache and by default @AuraEnabled executes with cacheable=false.
At the time of using it with wire, we have to explicitly make it true because wire uses browser cache.
Question 26. How can we able to communicate between two LWC components?
For communication in LWC we have different ways: Parent to Child, Child to Parent, Lightning Message Service.
Parent to child – To establish this type of communication we use @api decorator in LWC as it can expose that variable public which helps us to communicate with another component.
Child to Parent – To implement this we dispatch the event from the child and catch it in the parent.
Lightning Message Service – Here we create the Channel and one component will be the publisher from which we want to send the data and one will be the subscriber who receives the data.
Question 27. Business Scenario
Suppose I have a batch running and in the start, it fetches around 1000 records of accounts and the batch is running in 5 so each batch will take 200 records with it. In the execute method I have a loop running over that list of accounts. I am updating the account record in the loop. Now what could be the possible governor limit I can hit?
Below is the code for the batch:
Here the possible limit I can hit is LimitException because we are updating in the loop and when the scope is getting 200 records. The DML limit per transaction for Batch is 150 so as soon as I get the 151th record in the loop I’ll get the error.
error for batch
Question 28. What is event bubbling and event capturing in LWC?
Event bubbling and capturing are basically the concepts of JavaScript. In Event bubbling child component propagates up through the Parent component which is the default behaviour we can see in the LWC while we implement child-to-parent.
Event capturing is the opposite of Bubbling, here component will propagate downward to the child from the Parent. It is not the default behaviour we have to explicitly make it true.
Suppose we have 3 components childComp, parentComp, and grandParentComp and we want to communicate from child to grandparent then while dispatching the event we can set the bubble and composed property as true so that the event can move up to a higher hierarchy And can easily cross the Shadow boundary.
Question 29. What are deep copy and shallow copy of objects?
Shallow copy creates the copy of an object but not for its nested properties. It creates a reference to it. So any changes to the nested properties of a copied object will also change to the original one. Like spread operator creates the shallow copy.
Hence you can see above the copied object and the original both get changed for the nested object.
But for a deep copy, it is different, it creates the copy without actually referencing them so any changes in the copied object will not affect the original one and by JSON.stringify(JSON.parse(obj1)) we can create the deep copy of objects.