Apex Class Notes – Advanced Topics
The following is a portion of the notes that I took while viewing the Apex Training class, which is part of the Spring 2013 Premier Online Training available from Salesforce. This training class is one of the recommended training courses needed to complete the Salesforce Force.com Advanced Developer certification. Go here to get a PDF copy of the entire class notes.
Dynamic Apex Components
- Enables you to create more flexible applications by providing you the ability to access sObject and field metadata descriptions
- Allows you to write dynamic SOQL and SOSL queries and dynamic DML
- Consists of several components:
- Schema Describe – way to programmatically discover info about the current org schema. You can use the following to get a map of the schema:
Map<String,Schema.sObjectType> gd = Schema.getGlobalDescribe();- Dynamic SOQL – allows you to build a SOQL string at runtime. These are vulnerable to SOQL injection. To avoid this, you need to use the escapeSingleQuotes method. This method adds the escape character (\) to all single quotation marks in a string that is passed by a user.
- Dynamic SOSL – creates a SOSL string at runtime. Like with dynamic SOQL, you use escapeSingleQuotes(string) to prevent SOSL injection.
- Dynamic DML – provides the ability to perform DML operations on sObjects in which the type of the object is not known.
Apex Describe structures
- Token - lightweight reference to an sObject or a field
- It can be compared using the equality operator (==)
- It uses the getDescribe() method to get describe result objects of a particular sObject or field
- Describe result – contains all the describe properties for the sObject or field
Steps to Work with Describe Information
- Generate a list or map of tokens for the sObjects in your org
- Determine the sObject you need to access
- Generate the describe result for the sObject
- Generate a map of the field tokens for the sObject
- Generate the describe result for the field the script needs to access
Regular Expressions Matching Process
To match regular expressions using Pattern and Matcher classes, do the following:
- Instantiate a pattern object from the expression you wish to match
- Instantiate a matcher object from the pattern that contains the string you want to check
- Use the matcher object to detect if the matcher matches the pattern
Batch Apex
You can use Batch Apex to do the following:
- Improve processing of data
- Perform asynchronous batch processing
- Create batch items that can be processed asynchronously due to large data volumes or complex processes
- Build and deploy complex business processes
- Operate over entire datasets
- Leverage the power and flexibility of the Force.com platform
Database.Batchable
The Database.Batchable interface contains the following 3 methods:
- Start() – called at the beginning of a batch apex job and is used to collect records or objects passed to the execute method. It will return either a Database.QueryLocator object or an iterable
- Execute() – Is called for each batch item passed to the method. It is used to perform all required processing for each chunk of data
- Finish() – Is called after all batches are processed and is used to send confirmation emails
Apex Scheduler
- Schedule an Apex process such as data cleansing
- Set a date window and a preferred start time
- Set a weekly or monthly reoccurrence
- Set up to 25 active schedule
- Review the schedule status
Apex Class Notes – Receiving and Sending Emails Through Apex
The following is a portion of the notes that I took while viewing the Apex Training class, which is part of the Spring 2013 Premier Online Training available from Salesforce. This training class is one of the recommended training courses needed to complete the Salesforce Force.com Advanced Developer certification. Go here to get a PDF copy of the entire class notes.
Inbound Email Services
- Automated process that uses Apex classes to process the content, headers and attachments from inbound emails to a salesforce.com email address.
- Each email service has one or more salesforce-generated email addresses to which users can send a message for processing.
- An email service only processes messages it receives at one of it’s addresses. For example, you can create an email service that automatically creates contact records based on contact info in the email message.
- Your organization is limited in that it can only process (1000 * number of user licenses) messages per day for all email services. Anything above that limit will be bounced, discarded or queued, depending on how the email service was configured.
- Any target email address that is created in sandbox cannot be deployed to a production org
Setting up Inbound Services
- Create the email handler class shell – Basically this is a global class that implements the Messaging.InboundEmailHandler class. You can view a template for creating this class by going to Setup -> Develop -> Email Services
- Configure an email service – Click Setup -> Develop -> Email Services -> New Email Service. From here, you enter an Email Service Name, the name of the class you created in step 1, and a type of attachment that will be accepted. You can also specify advanced email security settings to verify the legitimacy of the sending server (such as SPF, SenderId, and DomainKeys)
- Complete the email handler class – Will include the following Messaging objects
- InboundEmail – contains the following:
- fromAddress
- toAddress
- Subject
- htmlBody
- plainTextBody
- binaryAttachments
- textAttachments
- InboundEmailResult – returns the result of the email service and sets the success flag in the exception handler class to true if the email delivery was successful
- InboundEnvelope – stores the envelope or header info associated with the inbound email
- Handling Attachments – notice that it handles text and binary attachments differently, thus they have to be processed in separate loops.
- Configure failure response settings – Determine how the service responds when an attempt to access the email service fails. Some of the actions include the following:
- Over Email Rate Limit Action – If the limits for all services has reached the daily limit of 1000 * # of user licenses/day
- Deactivated Email Address Action – If the email address is invalid
- Deactivated Email Service Action – If the service is inactive
- Unauthenticated Sender Action – If the authenticated sender checkbox is selected and it fails to authenticate
- Unauthorized Sender Action – If the users are not listed in the Accept Email From text box
- Bounce Message – Returns message to sender with a reason for the rejection
- Discard Message – Deletes the message and does not notify the sender
- Requeue Message – queues the message for processing in next 24 hours
- Generate target email addresses – to do this, do the following:
- Click the New Email Address button that opens up the Email Address Information window.
- Each salesforce email address is case-sensitive and you only need to specify the local part of the email address, since salesforce will assign the domain name part of the address.
- You need to specify a context user that the Apex class will run as
- You can also include a list of authorized domains or complete email addresses from where emails can be accepted
- Activate service email addresses
- Test inbound email
Email Logs
- Are csv files that can be accessed by clicking setup -> Monitoring -> Email Log Files. The logs contain the emails sent/received through salesforce along with the email addresses, date/time, delivery status and error codes.
- Since developers do not have access to system log files in the context of an inbound email class, they may want to create a custom object to log any exceptions or debug statements.
Outbound Email Services
- Emails can be written in plain test or HTML format
- The Messaging.sendEmail method is used to send emails (can send single or mass emails)
- Email templates can be references to reuse functionalities
- Visualforce pages used as templates provide more template flexibility that the standard email templates
- sendEmail method returns a sendEmailResult object. This contains two properties:
- isSucess, which tells whether the email was accepted
- sendEmailError , which is a list that contains field names, the text of the error message, status codes, and the ID of the target record
Features of Outbound Emails
- Org Limits on the number of sendEmail calls include:
- No more than 10 sendEmails methods for each context
- All single and mass emails sent from Apex count against the daily mass mail limit and when it is reached, all calls are rejected
- There are separate limits for emails sent using workflow and approval–related processes, which include:
- No more than 1000 email alerts per license/per org
- Daily email limit for overall org is 2 million and when reached, a warning email is sent to default workflow user and system admin
- No more than 1000 emails can be sent to external email addresses/day
- There is no limit to the number of internal emails that can be received
Email Security
- Emails from Salesforce can be configured to automatically comply with SPF and SenderId security frameworks
- SPF modifies the From address of an inbound email to a Salesforce.com email address to verify it’s legitimacy
- Enable SenderId compliance to automatically populate the sender field of every email sent from Salesforce with no-reply@salesforce.com
- The SenderId compliance enables the receiving mail servers to verify the sender of an email
- InboundEmail – contains the following:
Lessons Learned While Writing Apex Code
I have been writing object-oriented code for several years and specifically writing Apex code for over a year now, yet every time I go to create a new class or a trigger, I feel like I learn something brand new. This post is a summary of some of the most important lessons I have learned. I hope it helps you to avoid some of the same speed bumps that I have encountered.
Tip #1 – Make sure you “Bulkify” every Trigger
This is “THE BIGGEST TIP”. It is probably the one you will see the most written about, but it is so critical to writing good code, that I think it is ok to re-stress the point. In case you do not know, bulkifying a trigger means that the trigger can effectively handle being executed numerous times (200 times typically). 
Why 200?
Well that is usually the maximum number of times it can be executed (depending on the context). You see, your trigger can be executed multiple ways. It can be executed by users performing actions in Salesforce, or it can be executed by someone bulk loading data through the Apex Data Loader or the API. If your code is not written efficiently, it could very well throw the dreaded “Too Many SOQL Queries”. Trust me, you do not want to see this message.
So how do you avoid it?
Glad you asked. I am not going to bore you with a long detailed explanation of what you can do to bulkify your triggers, because honestly that has been done to death. I will however, tell you the golden rule to remember when writing triggers:
“If any of the following statements (SELECT,UPDATE, INSERT,DELETE) appear within a for loop, your code needs work.”Basically, if any of those statements (which represent either a SOQL Query or a DML statement) appears in a for loop, this means you are executing a very expensive operation numerous times (or at least as many times as the loop iterates, perhaps even more). Avoiding expensive database calls is a common thing to avoid in any programming language, but is especially important for Apex development because of Salesforce’s Governor Limits (which imho are GREAT for ensuring that we all create the best code possible).
If you want to learn more about all the things you can do to bulkify your triggers, check out this very informative post by Salesforce Guru, Jeff Douglas. Everyone should also checkout the post on the DeveloperForce Wiki titled, “Apex Code Best Practices“.
Tip #2 – Create at least two testMethods in your Unit Test Code
Most posts or instructions I read did not really stress the importance of creating both a single instance and bulk instance testMethod in your test class.
Why two methods and not just one?
The first method should be for testing what happens when a single record is handled. It is here that you should include System.AssertEquals to test whether a condition is true. This will tell you whether the trigger actually did what it was supposed to do.
It is possible to write Unit Test code that does not do this kind of check and still get 100% coverage. However, I would not consider the test to be a good one and neither should you.
The second test method should cover what happens when the trigger must handle multiple records. The following code is an example of using two such methods to test the validity of a trigger.
Tip #3 – Bulkifying your code is not just important for triggers
So what else is it important for?
How about Unit test code contained in class files – especially the ones that were built while keeping tip #2 in mind. That’s right, even your unit test code needs to be written efficiently – especially when it is set to execute a bulk testMethod.
If your Unit Test code uses a For loop to create a set of records and performs a SOQL query or a DML statement within that loop, guess what? Not only might you get an error, but your code is going to take way longer than it should to run tests and ultimately deploy.
This tip also applies to methods contained within a Helper class. The more efficient your code, the better, so always assume the worst and expect all of your code to be called multiple times.
Tip #4 – Use Both the Developer Console AND the Force.com IDE
I have been very impressed with the newly available Developers Console. For a long time, the Force.com IDE was hands down the best tool for developing Apex code, but I feel like that is starting to shift – a bit, at least.
For some tasks, I prefer using the Force.com IDE – like for just browsing and editing code. I also love the schema editor for examining metadata. However, I am discovering that there are certain tasks that I prefer the Developer Console for.
The biggest thing is for running Unit Tests. In my experience, the Developer Console is many times faster at executing unit tests – especially the ones that test bulk methods.
I also like the way the execute anonymous code area is right at the top of the Console. It just makes more sense to me in this spot. I also like the layout of the Query Editor tab and especially that it returns the value of an AggregateResult (see image below). This is something you cannot do with a query in the Schema Editor of the Force.com IDE
If you have not checked out the Developer Console or only glanced at it, I encourage you to give it a look. Try doing some tasks in one tool and then switch to doing the same task in the other tool. You may be surprised by which you prefer.
Tip #5 – Periodically go back and evaluate old code
Just like no two people will likely write the same identical answer to an essay test, no two developers will write the same development code (unless of course, you copy someone else’s code). There are dozens, maybe hundreds of ways to code some things and most ways involve inefficient code. Chances are high that you have written at least one piece of code that can be improved.
Learning how to be an efficient developer is a process. You do not learn it by reading one article, one book, or one post. It takes time to develop the skills to write efficient code in every situation – especially when you are new to a platform or language. Set aside time (say once a year) to periodically go back and evaluate old code you have written. You will probably be surprised at how much you can learn in a year.
Apex Class Notes – Working with Web Services
The following is a portion of the notes that I took while viewing the Apex Training class, which is part of the Spring 2013 Premier Online Training available from Salesforce. This training class is one of the recommended training courses needed to complete the Salesforce Force.com Advanced Developer certification. Go here to get a PDF copy of the entire class notes.
Custom Web Services
- The webservice keyword allows developers to create their own SOAP Web Services and defines methods that are inherently global
- Two ways to invoke Web Services:
- From the AJAX toolkit by importing the apex.js library and call the execute method
- From a client program by importing the WSDL and calling the custom method directly
- Access WSDL support through Setup -> Develop -> Classes
Guidelines for Creating Custom Web Services
- Must be static and cannot be overloaded
- Method signatures cannot include exceptions, maps, sets, matchers, or patterns
- Webservice keyword cannot be used in any code contained in a trigger
- A SOAP request or response cannot be bigger than 3MB
- The max size of the a SOAP request/response is regulated by the governor limit
- Webservice methods execute as System by default and can be changed with the “with sharing” keyword.
- @ReadOnly annotation can be used with web services to allow unrestricted queries when no DML operations are necessary.
SOAP Web Service Callouts
- Web services are called from external sources using SOAP Web Service Callouts
- Functionality is grouped based on business processes and is packaged as interoperable services.
- Functions are separated into distinct units or services, which are available over the network so that these can be combined and reused to produce business applications.
- External Web Services can be called natively from Apex by using SOAP Web Service Callouts
WSDL Support and Limitations
- Apex supports a limited set of WSDL schema types. It also supports the element and sequence WSDL schema constructs, as well as Blob, decimal and enum for call ins, but not for call outs.
- Apex does NOT support encoded services
- It also does not support WSD files with multiple portTypes, multiple services, or multiple bindings.
- WSDL files with imports are NOT supported
- It may be necessary to do a standard HTTP callout using a web services API such as RESTful web Services API.
HTTP Headers
- Can be set on a web service callout to set the value of a cookie in an authorization header.
- Can add inputHttpHeaders_x and outputHttpHeaders_c to an instance of your generated WSDL class.
- inputHttpHeaders is used to set authorization or cookie information
- outputHttpHeaders can be used to read the HTTP response headers returned after an HTTP request
Client Certificates
- Developers can send a client certificate with their callout to authenticate an HTTPS connection with a specified value.
- You can download a certificate through setup -> Security Controls -> Certificate and Key Management
- Create either a self-signed or CA-signed certificate
- Import the certificate on the remote application server that is being contacted as part of Web Service Integration
- You can also use Setup -> Developer -> API -> Generate Client Certificate to generate a client certificate for inbound calls, but not outbound ones.
Runtime Callout Considerations
- Request/Response must be no more than 3MB
- A short duration custom timeout can be defined
- A single Apex transaction can make a maximum of 10 callouts with a total request time of 120 seconds
- A circular reference can occur between Apex methods
- More than one loopback connections to Salesforce are not allowed
- To allow an endpoint to be accessed, it should be registered in Setup -> Security Controls -> Remote Site Settings. This is also known as whitelisting an endpoint, which tells Salesforce that it is ok to accept requests from this site.
Invoke an Imported web Service
- Successful importation of an external WSDL will generate an Apex stub (proxy) class
- Use the stub instance to setup your authorization credentials for the external service
- Use the stub to make external service method calls
RESTful Service Callouts
- Stands for Representational State Transfer
- Builds on the existing structure of the web by using HTTP verbs such as POST, GET, PUT, and DELETE
- A RESTFul service is called by hitting the resource URL, which can be pasted directly into a web browser (must be one line with no breaks).
- Simply sends and receives XML or JSON (Javascript Object Notation) data over HTTP
- Apex provides helper classes to parse and render XML and JSON data structures
XML Classes
- Callouts can be made from Apex where WSDL is not imported
- External web services can be accessed using HTTP callouts
- Send HTTP requests such as GET, POST, and PUT and also handle responses returned by request
- The XML Stream classes provide methods that make it easy to read and write XML strings
- XMLStreamReader class is used to read through XML responses returned from callouts and enables forward, read-only access to XML data returned from an HTTP callout
- XMLStreamWriter class is used to create an XML document and enables the writing of XML data.
- Document and XMLNode classes can be used as an alternative to XML classes
JSON Classes
- The JSON class provides methods to serialize and deserialize JSON content
- JSONGenerator class is used to serialize Apex objects into JSON content and enables the generation of standard JSON-encoded content
- JSONParser class is a parser for JSON-encoded content. It is used to parse a response that’s returned from a call to an external service that is in JSON format
Classes to make RESTful callouts
- HTTP class is used to sned an HTTPRequest and receive an HTTPResponse. It has only one method, send(), which takes one HTTPRequest argument and returns an HTTPResponse
- HTTPRequest class is used to programmatically create HTTP requests. It has several methods, such as:
- setEndpoint
- setBody
- setHeader
- setMethod
- setClientCertificate
- getEndpoint
- getBody
- getHeader
- getMethod
- HTTPResponse class is used to programtically handle the HTTP response returned by HTTP. It has several methods, such as:
- getStatus
- getStatusCode
- getHeader
- getHeaderKeys
- getBody
- getXMLStreamReader
RESTful Callout Example
public class HttpCalloutSample {
//pass in the endpoint to be used using the string url
public String getContent(String url) {
//Instantiate a new HTTP object
Http h = new Http();
//Instantiate a new Http request, specify the method (GET) as well as the endpoint
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod(‘GET’);
//Send the request and return a response
HttpResponse res = h.send(req);
Return res.getBody();
}
}
HTTP Helper Classes
- EncodingUtil class helps to encode and decode URL strings and includes the following methods:
- Base64Decode – converts a Base64-encoded String to a Blob
- Base64Encode – converts a Blob to an un-encoded string
- convertToHex – returns a hexadecimal (base 16) representation of the input string
- urlDecode – decodes a string using “UTF-8”
- urlEncode – encodes a string
- Cryto class enables access to external services that require encryption and includes the following:
- Encypt – encrypts the blob clearText using the specified algorithm. Use when you want to specify your own initialization vector
- Decrypt – decrypts the blob cipherText using the specified algorithm
- Sign – computes a unique digital signature for the input string using the supplied private key and the specified algorithm. This method supports the RSA-SHA1 or RSA algorithm
- generateMAC – computes a message authentication code or MAC for the input string using the private key and specified algorithm. Supports the HmacSHA1 algorithm
- generateDigest – computes a secure, one-way hash digest based on the supplied input string and algorithm name. Supports algorithms such as Md5 and SHA1
- generateAESKey – generates an Advanced Encryption Standard (AES) key. You can size to specify the keys size in bits
Apex REST-based Web Services
- You can implement custom web services in Apex and expose them through the REST architecture by using Apex REST.
- To do this, you first define your class with @RestResource annotation to expose it as a REST web service
- You also annotate methods to be exposed with the appropriate HTTP method. The following methods are available:
- HttpDelete
- HttpGet
- HttpPatch
- HttpPost
- HttpPut
- You must define your methods as global static. For example:
@RestResource (urlMapping=’/contact/v1/*’)
global class MyRESTService {
@httpPost
Global static Id doPost (String cLastName, Account a) {
Contact c = new Contact(LastName = cLastName, AccountId = a.Id);
Insert c;
Return c.id;
}
}Additional Apex Support for REST Web Services
- RestContext object contains the RestRequest and RestResponse objects
- Methods with @HttpGet or @HttpDelete annotations should have no parameters
- Use user-defined types for parameters in Apex REST methods
- JSON and XML formats are used to represent resources
Using REST-based web Services
- You can invoke a REST-based web service through an appropriate HTTP request and a URL, which includes a location of the Salesforce server, an Apex REST service, and a resource.
- It is best to try and find an exact match. If you cannot find an exact match, then find all the patterns with wildcards that match, and then select the longest of those by string length. If you cannot find a wildcard match, then an HTTP response status code 404 will be returned.
Asynchronous Apex
- If any Apex process takes more than 5 seconds, you should consider moving it to asynchronous Apex.
- To identify methods that are asynchronously executed, use the @future annotation. These must be static and can only return a void type
- Use the @future annotation to make a web services callout from a trigger
- A max of 10 method calls per Apex invocation are allowed
- A max of 200 @future method calls per Salesforce license per 24 hours are allowed
- The parameters passed to an asynchronous method must be primitive datatypes
- Methods with the @future annotation cannot be used in getter/setter methods or constructors of Visualforce controllers
- The asynchronous Apex code starts a new governor limit transaction context when it is run.
- When you use a trigger to call an external service; that service needs to support batch processing similar to Force.com API; otherwise making 1 callout per record in a bulk trigger will quickly exceed governor limits
Apex Class Notes – Exceptions, Debugging and Testing
The following is a portion of the notes that I took while viewing the Apex Training class, which is part of the Spring 2013 Premier Online Training available from Salesforce. This training class is one of the recommended training courses needed to complete the Salesforce Force.com Advanced Developer certification. Go here to get a PDF copy of the entire class notes.
Exceptions
- Records information about the error, the type of error and the state of the script or program when the error occurred
- Exceptions can be handled using the following keywords:
- Throw
- Try
- Catch
- Finally (optional)
- Syntax Example:
Try {
Update positions;
}
Catch (System.DmlException e) {
System.debug(‘DML Exception: ‘ + e.getDmlMessage(0));
}
Finally {
Positions.clear();
}
Exception Types
- System-defined Classes
- ListException
- DmlException
- MathException
- NullPointerException
- QueryException
- SecurityException
- SobjectException
- StringException
- TypeException
- User-defined Classes – created only if the system-defined exceptions do not offer required behavior
- Must end with the string Exception
- Must extend the system-defined Exception class
- Is a catch-all type of class
- Should be placed at the end of all catch blocks
- Example:
Public class MyCustomException extends Exception {}
Contact con = new Contact(LastName = ‘ContactLastname’);
Try {
Insert con;
} catch (DMLException e) {
Throw new MyCustomException(‘Could not create a contact ‘, e);
} finally {
System.debug(‘Tried to create a contact’);
}
System-Defined Exception Methods
- getMessage – returns message displayed to user
- getTypeName
- initCause(sObject Exception) – sets the cause if it is not set already
- getCause() – returns cause as an Exception object
- Methods that have DML in their name are only supported for DML exceptions. They are:
- getDmlFields(int) – returns names of the field(s) caused by the ith failed row
- getDmlIndex(int) – returns the original row position of the ith failed row
- getDmlMessage(int) – returns the user message for the ith failed row
- getDmlStatusCode(int) – returns the failure code for the ith failed row
- getNumDml – returns the number of the failed row
Debugging
- Two primary tools:
- Logs – such as the Developer console or the Debug Logs
- Anonymous Blocks – useful ad-hoc tool to execute code through the Force.com IDE
System Logs
- Can be viewed in the Salesforce UI or the IDE
- Is limited to 2MB per log
- Each org can retain up to 50MB of logs
- Log Filters:
- Database – log messages generated by calls to System.debug, DML Statements, or SOQL and SOSL queries
- Workflow – Info about workflow, assignment, auto-response, escalation rules
- Validation – Info about validation rules
- Callout – XML sent through web services
- Apex code – Info about Apex scripts, DML statements and queries, triggers and total resources used
- Apex profiling – Cumulative profiling info
- Visualforce – Info about Visualforce events
- System – Info about calls to all system methods
- System Log Levels:
- Error, Warm and Info
- Debug – calls to System.debug
- Fine, Finer – Includes calls to system.debug, every DML statement or inline query and entrance and exit for every user-defined procedure.
- Finest – Includes everything at fine or finer and addition info, such as variables declared, start of loops, thrown exceptions, static and class initialization and changes in sharing context.
- Debug Log Filters – You can raise the log levels for specific classes when debugging, as well as turn off logging for other classes. All classes and triggers inherit the settings from their caller unless overridden.
- Debug logs capture the same info as the system logs. You can get to them by going to Setup -> Monitoring -> Debug Logs. They are specific for a user
Anonymous Blocks
- Does not get stored and executes under the context of the current user. Primarily used to debug code on the fly, but it cannot include the static keyword.
- Can be executed one of 3 ways:
- Using the executeAnonymous() Web Services API call
- Developer Console within Salesforce
- Force.com IDE
Unit Testing
- Do not take arguments and do not commit data to the DB.
- Two ways to create:
- Using the TestMethod keyword
- Using the @isTest annotation
- The IDE has a template for creating Unit Test classes
- Governor limits are applied to unit tests
- Use the startTest and stopTest system static methods with testMethod to test governor limits.
- These methods may only be called once within each testMethod.
- Insert the startTest method after all of the test infrastructure has been set and just prior to the actual methods to be tested
- Unit tests can be run through a call to the runTests method.
- The compileClasses and compileTriggers methods can be used to just compile code without testing to verify the syntax
- Ways to run Unit tests:
- From the Salesforce UI for all classes – Go to Setup -> Develop -> Apex Classes and click “Run All Tests” button.
- From the Salesforce UI for one class – First select the class and click the “Run Test” button.
- In the Force.com IDE – Right-click a class, select Force.com and Run Test. Better to run unit tests from here.
- From the runTests() web service method
- Best Practices:
- Use System.Asset() method to verify results
- Do not assume that record ID’s are in sequential order and use the ORDER BY keyword to ensure that records are returned in expected order.
- Make sure that code can handle more than 200 records
- Use System.Runas() to test record sharing
Apex Class Notes – Implementing Triggers
The following is a portion of the notes that I took while viewing the Apex Training class, which is part of the Spring 2013 Premier Online Training available from Salesforce. This training class is one of the recommended training courses needed to complete the Salesforce Force.com Advanced Developer certification. Go here to get a PDF copy of the entire class notes.
Triggers
- Executes code when a DML event occurs on a specific sObject
- Can be created on any custom or standard object
- Two types:
- Before – can update or validate values before they are saved to the DB
- After
- Syntax:
Trigger <triggerName> on <ObjectName> (<trigger_events>) {
//code block
}
- Trigger Events:
- Before insert
- Before update
- Before delete
- After insert
- After update
- After delete
- After undelete
- To create triggers through the UI, you go to the object and select Triggers. You go through customize if it is a standard object and Create -> Objects if it is a custom object.
Trigger Execution Order:
- Original record is loaded from the DB
- The new record field values are loaded and old values are overwritten
- System Validation rules are executed and required fields are verified
- All before triggers are executed
- Most system validation steps are run again and validation rules are checked
- The record is saved to the DB, but not committed
- All after triggers are executed
- Assignment rules, auto-response rules, and workflow rules are executed
- Records are updated again if workflow fields are updated
- Before and after triggers are executed again if fields are updated based on workflow rules
- Escalation rules are executed
- Rollup summary formula or cross-object formula fields are updated in the parent records and affected records are saved
- Repeat the same process for affected grandparent records
- Criteria based sharing evaluation is executed
- All DML operations are committed to the DB
- Post-commit logic is executed
Types of Trigger Context Variables
- Trigger context Boolean Variables, such as Trigger.isBefore and Trigger.isInsert
- Size – returns total # of new and old records
- New – returns a list of the new versions of the sObject records. But is used only for insert and update triggers and can be modified only when used with before triggers
- newMap – returns a map of ID’s for the new versions of sObject records and is used only for update, insert or afterUndelete triggers
- old – returns the current version of the records and is used only for update and delete triggers
- oldMap
- You use the newMap and oldMap ID to sObject maps to correlate records with query results
- You use the addError method to prevent DML operations from taking action on specific records. This is very useful for applying custom validation rules. It can be applied at the sObject or field level (which affects where the error message appears on the page). For example, the following code is used to prevent a user from deleting an opportunity with a quote:
Trigger opptrigger on Opportunity (before delete) {
For (Quote__c q : [Select opportunity__c from quote__c
where opportunity__c in : Trigger.oldMap.keySet()]) {
Trigger.oldMap.get(q.opportunity__c).addError(‘Cannot delete opportunity with a quote’);
}
}
- Trigger.new and old cannot be used as part of a DML operation
- Trigger.old is always read-only
- Trigger.new cannot be deleted
- You can modify field values before they are writer to the DB by using Trigger.new in before triggers
- When trigger.new is used in after triggers, it is not saved and an exception is thrown.
- Trigger.new[0] processes only the first record in a multi-record batch
Trigger Considerations
- Since all trigger can execute through API access, you have to assume it can process multiple records at a time.
- Trigger code cannot contain the static keyword and can only contain keywords applicable to an inner class.
- Cascading execution of triggers are part of the same execution context for governor limits
- Upsert events cause both the insert and update triggers to fire
- Merge events execute delete triggers for the unsuccessful records and update triggers for the successful records.
- The after undelete trigger works only with recovered records
- Undelete events run only on top-level objects
Manual Sharing vs. Apex Sharing
- Manual sharing occurs when the user clicks the Sharing button, but Apex sharing is a way to create custom sharing reasons and control access levels for those reasons using Apex scripts.
- Custom Apex Sharing reasons can only be created on custom objects
Apex Sharing
- The Apex sharing reason should be referred to at the rowCause of an object__Share record.
- Set the Object_Share.rowCause equal to the Schema.Object_Share.rowCause.ApexSharingReason. For example:
//Instantiate the sharing record
Candidate__Share cShare = new Candidate__Share();
//Set the rowCause of the sharing record
cShare.rowCause = schema.Candidate__Share.RowCause.Hiring_Manager__c;
- At times you may want to initialize or reset record access via the sharing model. You do this by executing a large batch job to recalculate the sharing tables or the access rights. This is done by writing an Apex class that implements the Database.Batchable interface. It must also implement the start, executeBatch and finish methods of the interface. The finish method is used to send confirmation emails or execute post processing operations.
Trigger Limits
Triggers can execute a max of 200 records at a time and if the number exceeds 200, then it executes the remaining amounts in chunks of 200
Apex Class Notes – Records in the Database
The following are a portion of the notes that I took while viewing the Apex Training class, which is part of the Spring 2013 Premier Online Training available from Salesforce. This training class is one of the recommended training courses needed to complete the Salesforce Force.com Advanced Developer certification. Go here to get a PDF copy of the entire class notes.
sObject Relationship Naming Syntax
- sObjects have different names depending on the relationship type. But either way, they are appended with __r. For example:
- Parent-to-child – plural version of the child object – Interviewers__r
- Child-to-parent – singular version of the parent object – Position__c
- Relationships are written in dot notation and strung together to eventually reach the field that you need. For example:
Review.job_application__r.position__r.status__c = ‘Closed’;
- There are two ways to reference a parent from a child:
- You can use the foreign key, such as this:
Job_Application__c ja1 = new Job_Application__c();
Ja1.position__c = ‘a05s000000WzeYIAW’;
- Or, you can reference using a reference to the remote sObject object, such as:
Job_Application__c ja2 – new Job_Application__c();
Ja2.position__r = new Position__c();
- In a parent-to-children relationship, one member variable on the parent object refers to the children objects. The member variable is a reference to a list of related sObjects. If there are multiple relationships from the child to the parent, the related list name will increment, such as job_applications1__r and job_applications2__r. For example:
Position__c p = new Position__c();
p.job_applications__r = new List<Job_Application__c>();
The default relationship name is based on the child object name and can be overridden in the field definition.
The diagram above shows two examples of how sObject relationships are named. The first applies to two standard sObjects and the second applies to two custom objects.
SOQL
- SOQL (Salesforce Object Query Language) statements are similar to the select statement in SQL and is case insensitive. It can be used in Apex as well as the Web Services API.
- If you get a “consider and Index filter” error, it means that you are returning too may records and need to use a WHERE clause to restrict the records returned.
- You can insert SOQL into Apex using square-brackets, such as:
[SELECT Name FROM Position__c]
- Alternatively, you can use the Database.query method, such as:
Database.query(‘SELECT ‘ + myFieldString + ‘ FROM ACCOUNT’)
- Can return 4 data types:
- List of sObjects – Used if statement returns multiple records
- Single sObject – Used if only one record is returned
- Integer – Result should be stored in variable of Integer data type
- List of Aggregate Results (when using GROUP BY)
SOQL Functions
- AVG()
- COUNT()
- COUNT_DISTINCT() – returns distinct non-null field values
- MIN()
- MAX()
- SUM()
- CALENDAR_MONTH() – returns a number, as do the ones below
- DAY_IN_MONTH()
- FISCAL_YEAR()
- WEEK_IN_YEAR()
SOQL Bindings
SQL Statements in square-brackets can reference an expression that is preceded by a colon. For example:
String jobtype = ‘Full Time’;
List<Position__c> positions;
Positions = [SELECT Name FROM Position__c WHERE Type__c = :jobtype];
SOQL Returned Data
- Only returns data for fields that are specified and exceptions are raised if you try to reference a field that was not returned in the query. However, the ID field is implicitly returned.
- A SOQL For loop can iterate through all sObject records returned. Two types supported:
- Iterating over a single variable:
For(Account a : [SELECT id, name FROM account WHERE name LIKE ‘Acme’]) {
System.debug(a.name);
}
- Iterating over a variable list: (processes records in blocks of 200 at a time)
For(List<Account> accts : [SELECT id, name FROM account WHERE name LIKE ‘Acme’])
{
For (Account acct :accts) {
//Your code without DML statements
}
Database.update(accts);
}
SOQL Keywords
- IN – used for bulk queries; Uses a Set or a List of sObjects as an argument
- LIKE
- AND/OR
- NOT – can negate in, like, and null keywords
- ORDER BY – sorts in ascending by default
- GROUP BY
- LIMIT – Returns top record when used with Order By.
- FOR UPDATE – Locks the returned record from being updated by another request
- ALL ROWS – returns both active and deleted records
SOQL Queries – Different Types of Joins
- Right-Outer join. For example, to get job applications w/ associated position data:
SELECT Name, Position__r.Dept__c FROM Job_Application__c
- Left-Outer join. For example, to get positions and related job application data:
SELECT Name, (SELECT Name FROM Job_Applications__r) FROM Position__c
- Semi-Join. For example, to get only positions with related job applications:
SELECT Name FROM Position__c WHERE Id IN (Select Position__c FROM Job_Application__c)
- Right Inner join. For example, to get only job applications with related positions:
SELECT Name, Status__c, Position__r.Name FROM Job_Application__c WHERE Position__c != null
- Right Anti join. For example, to get only job applications without related positions:
SELECT NAME, Status__c FROM Job_Application__c WHERE Position__c = null
- Left Anti join. For example, to get only positions without related job applications:
SELECT Name FROM Position__c WHERE Id NOT IN (SELECT Position__c FROM Job_Application__c)
- Right Inner Join without Remote Condition. For example, to get only job applications with certain related positions:
SELECT Name, Status__c, Position__r.Name FROM Job_Application__c WHERE Position__r.Dept__c = ‘Engineering’
Multi-Level Relationships
- Relationship names can be chained together to access grandparents
- You cannot specify more than 5 child-to-parent relationships and only one parent-to-child relationship
SOSL
- SOSL (Salesforce Object Search Language) queries enable text searches across multiple sObjects and returns a list of lists of sObjects.
- Returns all searchable fields (excluding dates, ids and numbers), by default
- Return only ID’s, by default
- For example:
List<List<sObject>> acmeObjects = [FIND ‘Acme’ RETURNING Account(Name), Opportunity(name)];
- Statement specifies:
- Text expressions
- Scope of fields to search
- List of objects and fields to retrieve
- Conditions for selecting rows in the source objects
- The basic structure includes the FIND clause
- Clauses:
- FIND – Specifies the search string surrounded by single quote. Can use * to do a wildcard search that matches one or more characters in the middle or the search string and ? to do a wildcard search that matches one character in the middle or at the end of the search string.
- IN – (optional) limits the types of fields to search. If not specified, it will search all text in all objects. You could specify that it search only email, name, phone, or sidebar fields
- RETURNING – (optional) limits the results to specified object types. If not specified, it will return the ID’s of all objects that are searchable
- WHERE – (optional)
SOQL vs SOSL
- SOQL is best when the sObject is predetermined and the result data needs to be joined. You should use SOSL when searches need to occur across multiple sObject types
DML Operations
- Can take two forms, but is always restricted to one sObject at a time
- Standalone statements. For example:
Account account = new Account(Name = ‘Universal Containers’);
Insert account;
- Database methods. For example:
Account account = new Account(Name = ‘Universal Containers’);
Database.insert(account);
- Database methods (Insert and update) include an optional allOrNone parameter that defaults to true. They will both return a SaveResult object (even if a single record is submitted). If a list of records is submitted, a List<Database.SaveResult> list object is returned. The Delete method will return a DeleteResult object.
- SaveResult object has 3 methods:
- ID(getID)
- List<Database.Error> getErrors();
- Boolean isSuccess()
- Database.DMLOptions – allows you to include additional information, such as Truncation behavior, Locale options, and trigger assignment rules. Can also be used to trigger email notifications based on specific events, such as:
- Creation of a new case or task
- Creation of a case comment
- Conversion of a case email to a contact
- New user email notification
- Password reset
- External ID’s can be used to establish foreign key relationships among sObjects. For example:
Account refAcct = new Account(externalId__c = ‘12345’);
Contact c = new Contact(account = refAcct, lastName = ‘kay’);
Upsert c;
- It is bad practice to execute dml operations or SOQL queries inside of for loops. For example, this is a better way of handling an update with a for loop:
For(List<Position__c> positionList :[SELECT id FROM Position__c]) {
For(Position__c p: positionList) {
//code block
}
Database.update(positionList);
}
Apex SOQL and DML Governor Limits
- When governor limits are reached, you can consider using Apex asynchronous batch processing for DML operations.
- If you exceed the total # of SOQL queries, move them outside of loops
- If you exceed the total # of executed script statements, reduce the number of loops
- If you exceed the # of DML statements, insert, update or delete records in bulk
- If you exceed the total # of records retrieved by SOQL queries, create selective queries that filter indexed fields, such as primary keys, foreign keys, name, audit dates, or external ID fields
Database Transactions
- If stand-alone commands are used, the transaction always executes completely or does not execute at all.
- If the method-based DML statements are used, the transaction level can be set through the allOrNothing parameter.
- You can define savepoints to control the transaction level and define logic for rolling back a section or a subset of the DML operation.
- Each setSavepoint and rollback counts against the total number of DML statements
Apex Class Notes – Object-Oriented Programming in Apex
The following are notes that I took while viewing the Apex Training class, which is part of the Spring 2013 Premier Online Training available from Salesforce. This training class is one of the recommended training courses needed to complete the Salesforce Force.com Advanced Developer certification. Go here to get a PDF copy of the entire class notes.
Classes
- A class is a template or blueprint from which objects are created.
- They consist of methods and attributes
- Are stored with the version of API that is used to compile it
- May contain other classes, known as inner classes (but these can only be one level deep)
- Even though Apex code is not case sensitive, it is recommended that you follow the Java naming convention
- Static methods and attributes can only be declared in a top-level class definition
- To create new exception classes, the Exception class must be extended
- Classes can be enabled or disabled for profiles and can only be 100,000 characters in length
Ways to Create Classes
- Through the UI:
- Go to Setup -> Develop and Apex Classes.
- Click “New” or “Generate from WSDL”
- Enter code or upload a WSDL
- Through a Force.com IDE project:
- Right-click the src folder and click New -> Apex Class (this is the recommended way)
Class Syntax:
private | public | global
[virtual | abstract | with sharing | without sharing | (none)]
Class ClassName [implements InterfaceNameList | (none)] [extends ClassOrInterfaceName | (none}] {
// The body of the class
}
- If global, the class is accessible everywhere. This must be used with the webService keyword. All methods, attributes and inner classes that are global must be within a global class
- If public, the class is visible across the application, org or namespace that comprises the class.
- If private is used for an inner class, the inner class is only accessible to the outer class. The default for inner classes is private.
- Top level or outer classes must have either a global or public keyword.
- A class can implement multiple interfaces, but it can only extend once class
- A class can cast as a superclass and verify an objects class using the instanceof keyword
- You can implement and extend classes using the keywords, virtual, abstract and extends
- Virtual declares that the class allows extensions and overrides, Classes that are virtual cannot be global.
- Abstract declares that the class contains abstract methods and can be extended. These classes just have a method signature and do not have code. You cannot instantiate an object of an abstract class until some other class extends it.
- The Extends keyword declares that the class is a subclass. The “super” keyword can be used to invoke constructors and methods from the parent class.
- All Apex code executes in the system mode and ignores all CRUD, field-level security and record sharing level privileges. You use with and without sharing keywords to implement sharing. By default a class will run in the without sharing mode.
- With sharing – This means that when performing DML operations, the user can only update records to which he or she has edit level access
- Without Sharing – This ensures that sharing model access is ignored and is referred to a running in system mode.
- Interfaces are classes that only include the method signature. The methods are not implemented in the interfaces. Apex supports both top-level and inner interfaces
Attributes Syntax:
modifiers dataType attributeName initialization;
For example:
public static final Integer MAX_AMOUNT = 200;
Methods Syntax:
Modifiers returnDataType methodName (inputParameterList) {
// method code
}
For example:
Public Integer getInt() {
Return myInt;
}
Method and Attribute Access Modifiers
- Private – Default access modifier, but is not available for top-level classes. It implies that the attribute or method is only available in the class where it is defined.
- Protected – Available only to inner classes
- Public – Can be used by an apex code in the application, org or namespace
- Global – Accessible by all Apex everywhere. Note that Apex code cannot be shared between orgs, with the exception of Web Services, which are accessible to everyone.
Static Methods and Attributes
- Static methods are accessed through the class itself and do not depend on an instance of a class
- Static attributes are used to store data that is used within the class. They can be used to prevent recursive logic by setting flags
Constants
- Assign a value to a constant only once either at declaration or initialization
- Define a constant using both the static and final keywords
Instantiating Objects
- Allows you to work with methods and attributes that are not defined as static
- After instantiating, you can refer to methods and attributes using the dot notation. For example:
TestObject myObject1 = new TextObject();
myObject1.myMethod();
- A constructor is a special method used to create an object of a class. It has the same name as the class and is the first method invoked in the class. It does not have an explicit return type and is available by default in each class as invisible and without parameters. It can be overloaded by defining multiple constructors with different parameters.
The “this” Keyword
- With dot Notation – Used to represent the current instance of the class and can call methods or set attributes that are public or are available.
- With Constructors – Developers can do constructor chaining by using the this keyword, but the this keyword must be the first statement in the constructor
Apex System-Delivered Classes
- System Class – Is a static class that contains only static methods. Includes the following:
- Debug()
- Now()
- Today()
- Assert()
- AssertEquals()
- AssertNotEquals()
- UserInfo Class – Mostly getter methods used to get details. For example:
- getUserId()
- getUserName()
- getUserRoleId()
- getFirstName()
- getLocale()
- getLanguage()
Limit Methods
- Can be used for debugging purposes. There are two versions of each built-in method. The first version returns the amount of resource being used and the second returns the total amount of the resource available. For example:
- getDMLRows()
- getDMLStatements()
- getHeapSize()
- getQueries()
- getQueryRows()
- getScriptstatements()
Apex Workflow and Approval Processing
- Apex process classes are used to submit workflow requests and process the results of those requests. The three classes provided are:
- ProcessRequest – Used to process the results from a workflow process
- ProcessSubmitRequest – Used to submit a workflow item for approval
- ProcessWorkItemRequest – Used to process an item after it is submitted







