Scenario based Salesforce interview questions.
1. Batch apex syntax.An asynchronous process is a process or function that executes a task "in the background" without the user having to wait for the task to finish.
Batch Apex is used to run large jobs (think thousands or millions of records!) that would exceed normal processing limits.
global class SampleBatch implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator(/* SOQL query*/);
}
global void execute(Database.BatchableContext bc, List <Account> listAccount) {
//logic
}
global void finish(Database.BatchableContext bc) {
}
}
Batch Apex to delete Accounts which are 7 days old in Salesforce.
global class deleteOldRecordsBatch implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext bc) {
Date sevenDaysBefore = System.today().addDays(-7);
String SOQL = 'SELECT Id FROM Account WHERE CreatedDate = : sevenDaysBefore';
return Database.getQueryLocator(SOQL);
}
global void execute(Database.BatchableContext bc, List <Account> listAccount) {
delete listAccount;
}
global void finish(Database.BatchableContext bc) {
}
}
2. Schedulable apex syntax: to run Apex classes at a specified time
global class SampleSchedulableClass implements Schedulable{
global void execute(SchedulableContext ctx){
SampleBatch batch = new SampleBatch();
Database.executebatch(batch, 200);
}
3. Future method syntax:
Future Apex is used to run processes in a separate thread, at a later time when system resources become available.
public class sampleFuture{
@future
public static void futureMethod(List<Id> accId){
// Logic
}
}
Future Method to update Accounts
public class AccountProcessor{
@future
public static void countContacts(List<Id> accId){
List<Account> lstOfAccounts = [Select Id, Number_of_Contacts__c, (Select Id from Contacts) from Account Where Id IN :accId];
List<Account> lstOfAcc = new List<Account>();
for(Account acc : lstOfAccounts){
if(acc != null){
Integer contCount = 0;
if(acc.Contacts != null && acc.Contacts.size()> 0)
contCount = acc.Contacts.size();
acc.Number_of_Contacts__c = contCount;
lstOfAcc.add(acc);
}
}
Update lstOfAcc;
}
}
4. Queueable apex syntax.
You can chain one job to another job by starting a second job from a running job. Chaining jobs is useful if you need to do some sequential processing.
public class SampleQueueable implements Queueable{
public void execute(QueueableContext qc){
// Logic
}
}
Create an Queueable Apex class that inserts Contacts for Accounts
public class AddPrimaryContact implements Queueable{
Contact con;
String state;
public AddPrimaryContact(Contact con, String state){
this.con = con;
this.state = state;
}
public void execute(QueueableContext qc){
List<Account> lstOfAccs = [SELECT Id FROM Account WHERE BillingState = :state LIMIT 200];
List<Contact> lstOfConts = new List<Contact>();
for(Account acc : lstOfAccs){
Contact conInst = con.clone(false,false,false,false);
conInst.AccountId = acc.Id;
lstOfConts.add(conInst);
}
INSERT lstOfConts;
}
}
5. Soap inbound web service syntax.
global class AccountCreationWebServiceUsingSoap {
webservice static String createAccount(String accName) {
Account acc = new Account();
acc.Name = accName;
insert accName;
return stringValue; // response
}
}
6. Rest web service syntax.
@RestResource(urlMapping='/Account/*')
global with sharing class MyRestResource {
@HttpPost
global static String doPost(String name,
String phone, String website) {
Account account = new Account();
account.Name = name;
insert account;
return account.Id;
}
}
7. Rest callouts to send data to external syntax.
Apex Rest callout - POST:
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://th-apex-http-callout.herokuapp.com/animals');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json;charset=UTF-8');
request.setBody('{"name":"mighty moose"}');
HttpResponse response = http.send(request);
if (response.getStatusCode() != 201) {
System.debug('The status code returned was not expected: ' +
response.getStatusCode() + ' ' + response.getStatus());
} else {
System.debug(response.getBody());
}
8. Soap outbound webservice syntax.
public PageReference doSave(){
partnerSoapSforceCom.Soap sp = new partnerSoapSforceCom.Soap();
partnerSoapSforceCom.LoginResult log = sp.login('username, 'pwd');
soapSforceComSchemasClassAccountcre.SessionHeader_element SessionHeader =
new soapSforceComSchemasClassAccountcre.SessionHeader_element();
SessionHeader.sessionId = log.sessionId;
soapSforceComSchemasClassAccountcre.AccountCreationWebServiceUsingSoap AccountCreationWebService =
new soapSforceComSchemasClassAccountcre.AccountCreationWebServiceUsingSoap();
AccountCreationWebService.SessionHeader = SessionHeader;
}
partnerSoapSforceCom.Soap sp = new partnerSoapSforceCom.Soap();
partnerSoapSforceCom.LoginResult log = sp.login('username, 'pwd');
soapSforceComSchemasClassAccountcre.SessionHeader_element SessionHeader =
new soapSforceComSchemasClassAccountcre.SessionHeader_element();
SessionHeader.sessionId = log.sessionId;
soapSforceComSchemasClassAccountcre.AccountCreationWebServiceUsingSoap AccountCreationWebService =
new soapSforceComSchemasClassAccountcre.AccountCreationWebServiceUsingSoap();
AccountCreationWebService.SessionHeader = SessionHeader;
}
9. AURA Component to display records
Server Side Controller:
public with sharing class AccountCtrl {
@AuraEnabled
public static List<Account> getAccountData(){
return [select Id,Name, AccountNumber from Account limit 50];
}
}
Component
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes"
access="global"
controller="AccountCtrl">
<aura:handler name="init" value="{!this}" action="{!c.doinit}"/>
<aura:attribute name="Acclist" type="list"/>
<div>
<table class="slds-table slds-table_cell-buffer slds-table_bordered">
<thead>
<tr class="slds-line-height_reset">
<th class="slds-text-title_caps" scope="col">
<div class="slds-truncate" title="Account Name">Account Name</div>
</th>
</tr>
</thead>
<tbody>
<aura:iteration items="{!v.Acclist}" var="item" >
<tr class="slds-hint-parent">
<td data-label="Account Name">
<div class="slds-truncate" title="{!item.Name}">{!item.Name}</div>
</td>
</tr>
</aura:iteration>
</tbody>
</table>
</div>
</aura:component>
Client Side Controller
({
doinit: function(component) {
var action = component.get('c.getAccountData');
var self = this;
action.setCallback(this, function(actionResult) {
component.set('v.Acclist', actionResult.getReturnValue());
});
$A.enqueueAction(action);
}
})
Aura App:
<aura:application extends="force:slds">
<c:DisplayAccounts/>
</aura:application>
10. LWC to display records
Apex Class:
public class AccountController
{
@AuraEnabled(cacheable=true)
public static List<Account> displayAccounts(){
return [select Id, Name, Site from Account];
}
}
DisplayAccounts.html
<template>
<table class="slds-table slds-table_cell-buffer slds-table_bordered">
<tr>
<td><b>Name</b></td>
<td><b>Site</b></td>
<td><b>Action</b></td>
</tr>
<template for:each={accounts.data} for:item="acc">
<tr key={acc.Id}>
<td>
{acc.Name}
</td>
<td>
{acc.Site}
</td>
</tr>
</template>
</table>
</template>
</template>
DisplayAccounts.js
import { LightningElement,api,wire } from 'lwc';
import displayAccounts from '@salesforce/apex/AccountController.displayAccounts';
import updateRecord from '@salesforce/apex/AccountController.updateRecord';
import { refreshApex } from '@salesforce/apex';
export default class UpdateAccount extends LightningElement {
@api currentRecordId;
@api errorMessage;
@wire(displayAccounts) accounts;
}
LightningApplication
<aura:application extends="force:slds">
<c:DisplayAccounts/>
</aura:application>
11. Trigger to fetch values from Custom Metadata type and update in ISO__c field of Account:
Trigger updateIsoCode on Contact(before insert) {
List < Country_ISO_Code__mdt > countryIsoCodeMetadata = [SELECT Id,
Country__c, ISO_Code__c FROM Country_ISO_Code__mdt
];
Map < String, String > countryIsoCodeMap = new Map < String, String > ();
if (countryIsoCodeMetadata != null && countryIsoCodeMetadata.size() > 0) {
for (Country_ISO_Code__mdt cmd: countryIsoCodeMetadata) {
countryIsoCodeMap.put(cmd.Country__c, cmd.ISO_Code__c);
}
}
for (Contact con: Trigger.new) {
if (countryIsoCodeMap.containsKey(con.Country__c)) {
System.debug('inside Contact loop @@@ ' + countryIsoCodeMap);
con.ISO_Code__c = countryIsoCodeMap.get(con.Country__c);
}
}
}
12. Trigger to create Opportunity line item when Opportunity is created.
trigger Create_Opportunity_Line_Item_19 on Opportunity(after insert) {
Pricebook2 standardPb = [select id, name, isActive from Pricebook2 where IsStandard = true limit 1];
Product2 prd1 = new Product2(); // ----> Create product
prd1.Name = 'Accomodation';
prd1.isActive = true;
insert prd1;
System.debug(prd1);
PricebookEntry pbe1 = new PricebookEntry(); //------->Create PriceBookEntry
pbe1.Product2ID = prd1.id;
pbe1.Pricebook2ID = standardPb.id;
pbe1.UnitPrice = 50;
pbe1.isActive = true;
insert pbe1;
List < OpportunityLineItem > oplist = new List < OpportunityLineItem > (); //-->Create List to store OpportunityLineItem
for (Opportunity opp: Trigger.New) {
OpportunityLineItem oppli = new OpportunityLineItem(); //---->Create OpportunityLineItem.
oppli.PricebookEntryId = pbe1.Id;
oppli.OpportunityId = opp.Id;
oppli.Quantity = 5;
oppli.TotalPrice = 10.0;
oplist.add(oppli);
}
insert oplist; //----->insert OpportunityLineItem
}
13. Trigger to count Contacts of an Account incase of lookup relationship.
Trigger ContactCountTrigger on Contact(After insert, After Delete, After Undelete, After Update) {
Set < Id > setAccountIds = new Set < Id > ();
if (Trigger.isInsert || Trigger.isUndelete || Trigger.IsUpdate) {
for (Contact con: Trigger.new) {
setAccountIds.add(con.AccountId);
}
}
if (Trigger.isDelete) {
for (Contact con: Trigger.old) {
setAccountIds.add(con.AccountId);
}
}
List < Account > listAccs = [Select id, name, number_of_contacts__c,
(Select id from contacts) from Account
where Id in: setAccountIds
];
for (Account acc: listAccs) {
acc.number_of_contacts__c = acc.contacts.size();
}
update listAccs;
}
14. Trigger to delete/undelete child records when parent records are deleted/undeleted.
trigger DeleteContacts on Account(after delete) {
List < Contact > contacts = [SELECT AccountId FROM Contact
WHERE AccountId IN: Trigger.OldMap.keyset()
];
if (contacts != null && contacts.size() > 0) {
delete contacts;
}
}
15. Trigger to undelete contacts when Account is undeleted.
trigger undeleteContacts on Account(after undelete) {
List < Contact > contacts = [SELECT AccountId FROM Contact
WHERE AccountId IN: Trigger.OldMap.keyset()
AND IsDeleted = true ALL ROWS
];
if (contacts != null && contacts.size() > 0) {
undelete contacts;
}
}
16. Test class:
@isTest(seeAllData=false)
private class AccountTriggerWithHelperClass_Test{
static testMethod void testHelperClass(){
List<Account> listAccs = TestDataUtility.createAccounts();
insert listAccs;
}
}
17. Test Data utility class:
public class TestDataUtility{
public static List<Account> createAccounts(){
List<Account> accts = new List<Account>();
for(Integer i=0;i<20;i++) {
Account a = new Account(Name= ConstantsUtility.ACCOUNTNAME + i);
accts.add(a);
}
return accts;
}
}
18. Constants Utility class:
public class ConstantsUtility {
public static String ACCOUNTNAME = 'Test Account';
public static String ACCOUNTOBJ = 'Account';
public static String CONTACTOBJ = 'Contact';
}
public static String ACCOUNTNAME = 'Test Account';
public static String ACCOUNTOBJ = 'Account';
public static String CONTACTOBJ = 'Contact';
}
19. Apex XML parsing:
String strResp = '<?xml version="1.0" encoding="UTF-8"?><breakfast_menu> <food> <name>Belgian Waffles</name> <price>$5.95</price> <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description> <calories>650</calories> </food> <food> <name>Strawberry Belgian Waffles</name> <price>$7.95</price> <description>Light Belgian waffles covered with strawberries and whipped cream</description> <calories>900</calories> </food> <food> <name>Berry-Berry Belgian Waffles</name> <price>$8.95</price> <description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description> <calories>900</calories> </food> <food> <name>French Toast</name> <price>$4.50</price> <description>Thick slices made from our homemade sourdough bread</description> <calories>600</calories> </food> <food> <name>Homestyle Breakfast</name> <price>$6.95</price> <description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description> <calories>950</calories> </food></breakfast_menu>';
Dom.Document doc = new Dom.Document();
doc.load( strResp );
Dom.XMLNode rootElement = doc.getRootElement();
for ( Dom.XMLNode childElement : rootElement.getChildElements() ) {
for ( Dom.XMLNode detailElement : childElement.getChildElements() )
system.debug( detailElement.getName() + '-' + detailElement.getText() );
}
Output:
name-Belgian Waffles
price-$5.95
-
-
20. Database.SaveResult:
List<Account> listAccount = new List<Account>();
Account acc = new Account();
acc.Name = 'testAccount1';
Account acc2 = new Account();
acc2.Name = 'testAccount2';
listAccount.add(acc);
listAccount.add(acc2);
System.debug('listAccount '+listAccount);
if(listAccount != null && listAccount.size()>0){
Database.SaveResult[] srList = Database.insert(listAccount, false);
System.debug('srList ' +srList);
for(Database.SaveResult sr: srList){
if(sr.isSuccess()){
System.debug('Records inserted successfully '+sr.getId());
}
else
{
for(Database.Error objErr: sr.getErrors()){
System.debug('The following error has occurred ');
System.debug(objErr.getStatusCode() + ': '+objErr.getMessage());
System.debug('Error occurred by fields '+objErr.getFields());
}
}
}
}
21. Trigger to count, sum, min, max, avg of child records using Aggregate Result:
Trigger ContactAggregateResult on Contact(after insert){
Set<Id> accountIdSet = new Set<Id>();
Map<Id, Account> accountMap = new Map<Id, Account>();
for(Contact con: Trigger.new){
if(con.AccountId != null){
accountIdSet.add(con.AccountId);
}
}
if(accountIdSet != null){
for(AggregateResult ar: [SELECT count(Id) contactCount, sum(Amount__c) sumAmount,
avg(Amount__c) avgAmount, Max(Amount__c) maxAmount,
min(Amount__c) minAmount, AccountId FROM Contact
WHERE AccountId in: accountIdSet GROUP BY AccountId ])
{
Account acc = new Account();
acc.Id = (Id)ar.get('AccountId');
acc.Count_of_Contacts__c = (Integer)ar.get('contactCount');
acc.Sum_of_Contacts_Amount__c = (Decimal)ar.get('sumAmount');
acc.Max_of_Contacts_Amount__c = (Decimal)ar.get('maxAmount');
acc.Min_of_Contacts_Amount__c = (Decimal)ar.get('minAmount');
acc.Average_Of_Contacts_Amount__c = (Decimal)ar.get('avgAmount');
System.debug('Count @@@ '+acc.Count_of_Contacts__c);
System.debug('Sum @@@ '+acc.Sum_of_Contacts_Amount__c);
System.debug('Max @@@ '+acc.Max_of_Contacts_Amount__c);
System.debug('Min @@@ '+acc.Min_of_Contacts_Amount__c);
System.debug('Avg @@@ '+acc.Average_Of_Contacts_Amount__c);
accountMap.put(acc.Id, acc);
}
}
if(accountMap != null){
update accountMap.values();
}
}
22. Delete multiple object records using batch apex.
global class SampleBatchClass implements Database.Batchable<string>, Database.Stateful, Schedulable {
global boolean reRun = false;
global Set<string> setToAddresses = new Set<String>();
global Set<string> setCcAddresses = new Set<String>();
global List<string> setToAddressesList = new List<String>();
global List<string> setCcAddressesList = new List<String>();
global SampleBatchClass(){
for(CEP_Storage_Email__mdt mdt: [SELECT Label, Set_To_Addresses__c, Set_Cc_Addresses__c FROM CEP_Storage_Email__mdt
WHERE Active__c = TRUE LIMIT 50000 ])
{
if(mdt.Set_To_Addresses__c){
setToAddresses.add(mdt.Label);
}
if(mdt.Set_Cc_Addresses__c){
setCcAddresses.add(mdt.Label);
}
}
setToAddressesList = new List<String>(setToAddresses);
setCcAddressesList = new List<String>(setCcAddresses);
}
global Iterable<string> start(Database.BatchableContext ctx) {
Set<String> setMetadata = new Set<String>();
for(CEP_ObjectName__mdt mdt: [SELECT Label, Days__c FROM CEP_ObjectName__mdt WHERE Active__c = FALSE
/* AND Days__c != NULL AND Days__c = 90 */ LIMIT 50000])
{
//setMetadata.add(mdt.Label);
setMetadata.add(mdt.Label+'-'+mdt.Days__c); //
}
List<String> listMetadata = new List<String>(setMetadata);
return listMetadata;
}
global void execute(Database.BatchableContext ctx, list<string> lstsObjectName) {
list<sObject> objectRecords = new list<sObject>();
List<String> valueArray = new List<String>(); //
for(string strObjectName : lstsObjectName) {
valueArray = strObjectName.split('-'); //
System.debug('valueArray[0] $$$ '+valueArray[0]);
System.debug('valueArray[1] $$$ '+valueArray[1]);
Integer numV = Integer.valueOf(valueArray[1]);
for(sObject sObj : Database.query('SELECT Id FROM ' + valueArray[0] + ' WHERE CreatedDate < Last_N_days:' + Integer.valueOf(valueArray[1]) + ' limit 150')) {
System.debug('sObj $$$ '+sObj);
if(objectRecords.size() < 200*(500 - objectRecords.size()) + objectRecords.size()){ // Here 500 is batch size.
objectRecords.add(sObj);
}
else {
reRun = true;
break;
}
}
}
if(objectRecords != NULL && objectRecords.size()>0){
objectRecords.sort();
try{
database.delete(objectRecords, false);
}
catch(Exception ex){
System.debug('Exception occurred '+ex);
}
}
}
global void finish(Database.BatchableContext ctx) {
if(reRun) {
Database.executebatch(new SampleBatchClass());
}
if(!reRun) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
AsyncApexJob a = [SELECT a.TotalJobItems, a.Status, a.NumberOfErrors,
a.JobType, a.JobItemsProcessed, a.CompletedDate, a.ApexClassId
FROM AsyncApexJob a WHERE id = :ctx.getJobId()];
String sandboxUrl1=String.valueOf(System.Url.getOrgDomainUrl());
String sandboxUrl2=sandboxUrl1.replace('Url:[delegate=','');
String sandboxUrlValue = sandboxUrl2.replace(']','');
mail.setToAddresses(setToAddressesList);
mail.setCcAddresses(setCcAddressesList);
// mail.setReplyTo(Label.CEP_Set_Reply_To_Email_Address);
mail.setSenderDisplayName('Scheduled Batch Apex Processing');
mail.setSubject('Batch Apex Processing status for 7 days old records: '+a.Status);
String htmlBody = '';
//open table..
htmlBody ='Hi, <br/> <br/> As part of Platform Environment Management, the scheduled batch apex job has processed &
cleared all the test data which are created 7 days ago for specific objects.<br/><br/>';
htmlBody +='Please find below details of scheduled batch apex job.<br/><br/>';
htmlBody += '<table border="1" style="border-collapse: collapse">';
htmlBody += '<tr><td>' + ' Apex Job Processing status ' + '</td><td>' + ' '+ a.Status + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Total Batch Apex Job Items ' + '</td><td>' + ' ' + a.TotalJobItems + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Job Item processed ' + '</td><td>' + ' ' + a.JobItemsProcessed + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Number Of Failures ' + '</td><td>' + ' ' + a.NumberOfErrors + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Job Completed Date and Time ' + '</td><td>' + ' ' + a.CompletedDate + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Job Type ' + '</td><td>' + ' ' + a.JobType + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Apex Class Id ' + '</td><td>' + ' ' + a.ApexClassId + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Scheduled Apex Class Name ' + '</td><td>' + ' ' + 'CEP_BatchDelete7DaysOldRecords' + ' ' + '</td></tr>';
htmlBody += '<tr><td>' + ' Sandbox URL ' + '</td><td>' + ' ' + sandboxUrlValue + ' ' + '</td></tr>';
htmlBody += '</table>'; //close table
htmlBody +='<br/><br/>Thank you.<br/>';
mail.setHTMLBody(htmlBody);
Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail});
}
}
global void execute(SchedulableContext SC) {
Database.executebatch(new SampleBatchClass());
}
}
No comments:
Post a Comment