Friday, September 22, 2017

Salesforce Developer Beginner - Apex Basics & Database

Apex is a programming language that uses Java-like syntax and acts like database stored procedures. Apex enables developers to add business logic to system events, such as button clicks, updates of related records, and Visualforce pages.
As a language, Apex is:
  • Hosted—Apex is saved, compiled, and executed on the server—the Force.com platform.
  • Automatically upgradeable—Because compiled code is stored as metadata in the platform, Apex is automatically upgraded as part of Salesforce releases.
  • Object oriented—Apex supports classes, interfaces, and inheritance.
  • Strongly typed—Apex validates references to objects at compile time.
  • Multitenant aware—Because Apex runs in a multitenant platform, it guards closely against runaway code by enforcing limits, which prevent code from monopolizing shared resources.
  • Integrated with the database—It is straightforward to access and manipulate records. Apex provides direct access to records and their fields, and provides statements and query languages to manipulate those records.
  • Data focused—Apex provides transactional access to the database, allowing you to roll back operations.
  • Easy to use—Apex is based on familiar Java idioms.
  • Easy to test—Apex provides built-in support for unit test creation, execution, and code coverage. Salesforce ensures that all custom Apex code works as expected by executing all unit tests prior to any platform upgrades.
  • Versioned—Custom Apex code can be saved against different versions of the API.

Apex Language Highlights
Like other object-oriented programming languages, these are some of the language constructs that Apex supports:
  • Classes, interfaces, properties, and collections (including arrays).
  • Object and array notation.
  • Expressions, variables, and constants.
  • Conditional statements (if-then-else) and control flow statements (for loops and while loops).
Unlike other object-oriented programming languages, Apex supports:
  • Cloud development as Apex is stored, compiled, and executed in the cloud.
  • Triggers, which are similar to triggers in database systems.
  • Database statements that allow you to make direct database calls and query languages to query and search data.
  • Transactions and rollbacks.
  • The global access modifier, which is more permissive than the public modifier and allows access across namespaces and applications.
  • Versioning of custom code.
In addition, Apex is a case-insensitive language.

Development Tools

You can write Apex and access debugging information directly in the browser by using the Salesforce user interface. Open the Developer Console under Your Name or the quick access menu ().
You can also write Apex on a client by using the Force.com IDE plugin for Eclipse. See Force.com IDE on the Salesforce Developer site.
Data Types Overview
Apex supports various data types, including a data type specific to Salesforce—the sObject data type.
Apex supports the following data types.
  • A primitive, such as an Integer, Double, Long, Date, Datetime, String, ID, Boolean, among others.
  • An sObject, either as a generic sObject or as a specific sObject, such as an Account, Contact, or MyCustomObject__c (you’ll learn more about sObjects in a later unit.)
  • A collection, including:
    • A list (or array) of primitives, sObjects, user defined objects, objects created from Apex classes, or collections
    • A set of primitives
    • A map from a primitive to a primitive, sObject, or collection
  • A typed list of values, also known as an enum
  • User-defined Apex classes
  • System-supplied Apex classes

Apex Collections: List

Lists hold an ordered collection of objects. Lists in Apex are synonymous with arrays and the two can be used interchangeably.
The following two declarations are equivalent. The colors variable is declared using the List syntax.
List<String> colors = new List<String>();
Alternatively, the colors variable can be declared as an array but assigned to a list rather than an array.
String[] colors = new List<String>();
Generally, it’s easier to create a list rather than an array because lists don’t require you to determine ahead of time how many elements you need to allocate.
You can add elements to a list when creating the list, or after creating the list by calling the add() method. This first example shows you both ways of adding elements to a list.
// Create a list and add elements to it in one step
List<String> colors = new List<String> { 'red', 'green', 'blue' };
// Add elements to a list after it has been created
List<String> moreColors = new List<String>();
moreColors.add('orange');
moreColors.add('purple');
List elements can be read by specifying an index between square brackets, just like with array elements. Also, you can use the get() method to read a list element. This example is based on the lists created in the previous example and shows how to read list elements using either method. The example also shows how to iterate over array elements.

// Get elements from a list
String color1 = moreColors.get(0);
String color2 = moreColors[0];
System.assertEquals(color1, color2);

// Iterate over a list to read elements
for(Integer i=0;i<colors.size();i++) {
    // Write value to the debug log
    System.debug(colors[i]);
}

Lists

A list is an ordered collection of elements that are distinguished by their indices. List elements can be of any data type—primitive types, collections, sObjects, user-defined types, and built-in Apex types.
This table is a visual representation of a list of Strings:
Index 0Index 1Index 2Index 3Index 4Index 5
'Red''Orange''Yellow''Green''Blue''Purple'
The index position of the first element in a list is always 0.
Lists can contain any collection and can be nested within one another and become multidimensional. For example, you can have a list of lists of sets of Integers. A list can contain up to four levels of nested collections inside it, that is, a total of five levels overall.
To declare a list, use the List keyword followed by the primitive data, sObject, nested list, map, or set type within <> characters. For example:
// Create an empty list of String
List<String> my_list = new List<String>();
// Create a nested list
List<List<Set<Integer>>> my_list_2 = new List<List<Set<Integer>>>();

To access elements in a list, use the List methods provided by Apex. For example:

List<Integer> myList = new List<Integer>(); // Define a new list
myList.add(47);                    // Adds a second element of value 47 to the end 
                                       // of the list
Integer i = myList.get(0);                   // Retrieves the element at index 0
myList.set(0, 1);                           // Adds the integer 1 to the list at index 0
myList.clear();                    // Removes all elements from the list

For more information, including a complete list of all supported methods, see List Class.

Using Array Notation for One-Dimensional Lists

When using one-dimensional lists of primitives or objects, you can also use more traditional array notation to declare and reference list elements. For example, you can declare a one-dimensional list of primitives or objects by following the data type name with the [] characters:
String[] colors = new List<String>();
These two statements are equivalent to the previous:

List<String> colors = new String[1];

String[] colors = new String[1];

To reference an element of a one-dimensional list, you can also follow the name of the list with the element's index position in square brackets. For example:

colors[0] = 'Green';

Even though the size of the previous String array is defined as one element (the number between the brackets in newString[1]), lists are elastic and can grow as needed provided that you use the List add method to add new elements. For example, you can add two or more elements to the colors list. But if you’re using square brackets to add an element to a list, the list behaves like an array and isn’t elastic, that is, you won’t be allowed to add more elements than the declared array size.
All lists are initialized to null. Lists can be assigned values and allocated memory using literal notation. For example:
List<Integer> ints = new Integer[0]; // Defines an Integer list of size zero with no elements
List<Integer> ints = new Integer[6]; // Defines an Integer list with memory allocated for six Integers

Sets

A set is an unordered collection of elements that do not contain any duplicates. Set elements can be of any data type—primitive types, collections, sObjects, user-defined types, and built-in Apex types.
This table represents a set of strings that uses city names:
'San Francisco''New York''Paris''Tokyo'
Sets can contain collections that can be nested within one another. For example, you can have a set of lists of sets of Integers. A set can contain up to four levels of nested collections inside it, that is, up to five levels overall.
To declare a set, use the Set keyword followed by the primitive data type name within <> characters. For example:

new Set<String>()

The following are ways to declare and populate a set:

Set<String> s1 = new Set<String>{'a', 'b + c'}; // Defines a new set with two elements
Set<String> s2 = new Set<String>(s1); // Defines a new set that contains the 
                                     // elements of the set created in the previous step

To access elements in a set, use the system methods provided by Apex. For example:

Set<Integer> s = new Set<Integer>(); // Define a new set
s.add(1);                            // Add an element to the set
System.assert(s.contains(1));        // Assert that the set contains an element
s.remove(1);                         // Remove the element from the set

For more information, including a complete list of all supported set system methods, see Set Class.
Note the following limitations on sets:
  • Unlike Java, Apex developers do not need to reference the algorithm that is used to implement a set in their declarations (for example, HashSet or TreeSet). Apex uses a hash structure for all sets.
  • A set is an unordered collection—you can’t access a set element at a specific index. You can only iterate over set elements.
  • The iteration order of set elements is deterministic, so you can rely on the order being the same in each subsequent execution of the same code.

Maps

A map is a collection of key-value pairs where each unique key maps to a single value. Keys and values can be any data type—primitive types, collections, sObjects, user-defined types, and built-in Apex types.
This table represents a map of countries and currencies:
Country (Key)'United States''Japan''France''England''India'
Currency (Value)'Dollar''Yen''Euro''Pound''Rupee'
Map keys and values can contain any collection, and can contain nested collections. For example, you can have a map of Integers to maps, which, in turn, map Strings to lists. Map keys can contain up to only four levels of nested collections.
To declare a map, use the Map keyword followed by the data types of the key and the value within <> characters. For example:

Map<String, String> country_currencies = new Map<String, String>();
Map<ID, Set<String>> m = new Map<ID, Set<String>>();

You can use the generic or specific sObject data types with maps. You can also create a generic instance of a map.
As with lists, you can populate map key-value pairs when the map is declared by using curly brace ({}) syntax. Within the curly braces, specify the key first, then specify the value for that key using =>. For example:

Map<String, String> MyStrings = new Map<String, String>{'a' => 'b', 'c' => 'd'.toUpperCase()};

In the first example, the value for the key a is b, and the value for the key c is D.
To access elements in a map, use the Map methods provided by Apex. This example creates a map of integer keys and string values. It adds two entries, checks for the existence of the first key, retrieves the value for the second entry, and finally gets the set of all keys.

Map<Integer, String> m = new Map<Integer, String>(); // Define a new map
m.put(1, 'First entry');                  // Insert a new key-value pair in the map
m.put(2, 'Second entry');                  // Insert a new key-value pair in the map
System.assert(m.containsKey(1));  // Assert that the map contains a key
String value = m.get(2);               // Retrieve a value, given a particular key
System.assertEquals('Second entry', value);
Set<Integer> s = m.keySet();       // Return a set that contains all of the keys in the map

For more information, including a complete list of all supported Map methods, see Map Class.

Map Considerations

  • Unlike Java, Apex developers do not need to reference the algorithm that is used to implement a map in their declarations (for example, HashMap or TreeMap). Apex uses a hash structure for all maps.
  • The iteration order of map elements is deterministic. You can rely on the order being the same in each subsequent execution of the same code. However, we recommend to always access map elements by key.
  • A map key can hold the null value.
  • Adding a map entry with a key that matches an existing key in the map overwrites the existing entry with that key with the new entry.
  • Map keys of type String are case-sensitive. Two keys that differ only by the case are considered unique and have corresponding distinct Map entries. Subsequently, the Map methods, including putgetcontainsKey, and remove treat these keys as distinct.
  • Uniqueness of map keys of user-defined types is determined by the equals and hashCode methods, which you provide in your classes. Uniqueness of keys of all other non-primitive types, such as sObject keys, is determined by comparing the objects’ field values.
  • A Map object is serializable into JSON only if it uses one of the following data types as a key.

Apex Classes



One of the benefits of Apex classes is code reuse. Class methods can be called by triggers and other classes. The following tutorial walks you through saving an example class in your organization, using this class to send emails, and inspecting debug logs.

Save an Apex Class

Save the EmailManager class in your organization:
  1. Open the Developer Console under Your Name or the quick access menu ().
  2. In the Developer Console, click File | New | Apex Class, and enter EmailManager for the class name, and then click OK.
  3. Replace the default class body with the EmailManager class example.
    The EmailManager class has a public method (sendMail()) that sends email and uses built-in Messaging methods of the Apex class library. Also, this class has a private helper method (inspectResults()), which can’t be called externally because it is private but is used only within the class. This helper method inspects the results of the email send call and is called by sendMail().
  4. Click Ctrl+S to save your class.


public class EmailManager {



    // Public method
    public void sendMail(String address, String subject, String body) {
        // Create an email message object
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {address};
        mail.setToAddresses(toAddresses);
        mail.setSubject(subject);
        mail.setPlainTextBody(body);
        // Pass this email message to the built-in sendEmail method 
        // of the Messaging class
        Messaging.SendEmailResult[] results = Messaging.sendEmail(
                                 new Messaging.SingleEmailMessage[] { mail });
        
        // Call a helper method to inspect the returned results
        inspectResults(results);
    }
    
    // Helper method
    private static Boolean inspectResults(Messaging.SendEmailResult[] results) {
        Boolean sendResult = true;
        
        // sendEmail returns an array of result objects.
        // Iterate through the list to inspect results. 
        // In this class, the methods send only one email, 
        // so we should have only one result.
        for (Messaging.SendEmailResult res : results) {
            if (res.isSuccess()) {
                System.debug('Email sent successfully');
            }
            else {
                sendResult = false;
                System.debug('The following errors occurred: ' + res.getErrors());                 
            }
        }
        
        return sendResult;
    }

}

The class you just saved makes use of object-oriented programming (OOP). The class encapsulates the methods that are related to managing email. To be a perfect example of OOP, the class would also contain member variables (attributes) and accessor methods to access those attributes, but for simplicity our class doesn’t have these.
Salesforce compiles your class when you save it.

Call a Method to Send an Email

Let’s invoke the public method. We’ll use anonymous Apex execution to do so. Anonymous Apex allows you to run lines of code on the fly and is a handy way to invoke Apex, especially to test out functionality. Debug log results are generated, as with any other Apex execution.
There are other ways to invoke Apex, for example, through triggers. You’ll learn more about triggers in another module.
  1. In the Developer Console, click Debug | Open Execute Anonymous Window.
  2. In the window that opens, enter the following. Replace 'Your email address' with your email address.
  3. Click Execute.
EmailManager em = new EmailManager();
em.sendMail('Your email address', 'Trailhead Tutorial', '123 body');

  1. Now that this method has executed, you should have received an email in your inbox. Check your email!

Inspect Debug Logs

Debug logs are useful for debugging your code. When Apex methods execute, the calls are logged in the debug log. Also, you can write your own debug messages to the log, which helps in debugging your code in case there are errors. The inspectResults() helper method, which is called by sendMail(), writes messages to the log by using theSystem.debug() method to indicate whether the email send operation was successful or had errors. You can look for these messages in the debug log that was generated when you executed the method.
  1. In the Developer Console, click the Logs tab and double-click the most recent log in the list.
  2. Select Debug Only to filter the log so that only log lines for System.debug() statements are shown.

Also, you can filter the debug log by searching for any keyword in the Filter field, or by selecting any of the other options. For more information, see the Log Inspector help.

  1. You’ll see the following message in the filtered log view, assuming the email was sent without errors.
    DEBUG|Email sent successfully

Call a Static Method

Because the sendMail() method in our class doesn’t access class member variables, it doesn’t need to be an instance method. Let’s change it to a static method by adding the static keyword to its declaration. Static methods are easier to call than instance methods because they don’t need to be called on an instance of the class but are called directly on the class name.
  1. In the Developer Console, find the open tab for the EmailManager class and modify the first line of the sendMail()method definition to the following (the only change is the added static keyword.) 
    • public static void sendMail(String address, String subject, String body) {
  2. Save the class by pressing Ctrl+S.
  3. Modify the statements in your Execute Anonymous window to call the static method on the class name.
  4. Click Execute.
EmailManager.sendMail('Your email address', 'Trailhead Tutorial', '123 body');

Now that this method has executed, you can check your email, and optionally, the debug log as in the previous steps.

Create an Apex class that returns an array (or list) of strings.

Create an Apex class that returns an array (or list) of formatted strings ('Test 0', 'Test 1', ...). The length of the array is determined by an integer parameter.
  • The Apex class must be called 'StringArrayTest' and be in the public scope.
  • The Apex class must have a public static method called 'generateStringArray'.
  • The 'generateStringArray' method must return an array (or list) of strings. Each string must have a value in the format 'Test n' where n is the index of the current string in the array. The number of returned strings is specified by the integer parameter to the 'generateStringArray' method.


public class StringArrayTest {

    //Public Method

    public static String[] generateStringArray (Integer lenTest) {

        //Instantiate the list
        String[] lstTest = new List<String>();
        
        //Iterate throught the list
        for (Integer i=0;i<lenTest;i++){
            lstTest.add('Test ' + i);
            
            // Write value to the debug log
            System.debug(lstTest[i]);
        } //end loop
        
        return lstTest;
    }//end method
}// end class

Enter following in Execute Anonymous Apex Code in Developer Console:

StringArrayTest.generateStringArray(5);

Use sObjects



Because Apex is tightly integrated with the database, you can access Salesforce records and their fields directly from Apex. Every record in Salesforce is natively represented as an sObject in Apex. For example, the Acme account record corresponds to an Account sObject in Apex. The fields of the Acme record that you can view and modify in the user interface can be read and modified directly on the sObject as well.
The following table lists some populated fields of the Acme account example record. The Account sObject is an abstraction of the account record and holds the account field information in memory as an object.
Table 1. Account sObject for a Retrieved Record
Account Field
Value
Id
001D000000JlfXe
Name
Acme
Phone
(415)555-1212
NumberOfEmployees
100
Each Salesforce record is represented as an sObject before it is inserted into Salesforce. Likewise, when persisted records are retrieved from Salesforce, they’re stored in an sObject variable.
Standard and custom object records in Salesforce map to their sObject types in Apex. Here are some common sObject type names in Apex used for standard objects.
  • Account
  • Contact
  • Lead
  • Opportunity
If you’ve added custom objects in your organization, use the API names of the custom objects in Apex. For example, a custom object called Merchandise corresponds to the Merchandise__c sObject in Apex.

Creating sObject Variables

To create an sObject, you need to declare a variable and assign it to an sObject instance. The data type of the variable is the sObject type.
The following example creates an sObject variable of type Account and assigns it to a new account with the name Acme.
Account acct = new Account(Name='Acme');

sObject and Field Names

The names of sObjects correspond to the API names of the corresponding standard or custom objects. Similarly, the names of sObject fields correspond to the API names of the corresponding fields.
API names of object and fields can differ from their labels. For example, the Employees field has a label of Employees and appears on the account record page as Employees but its API name is NumberOfEmployees. To access this field in Apex, you’ll need to use the API name for the field: NumberOfEmployees.
The following are highlights of some rules used for API names for custom objects and custom fields.
For custom objects and custom fields, the API name always ends with the __c suffix. For custom relationship fields, the API name ends with the __r suffix. For example:
  • A custom object with a label of Merchandise has an API name of Merchandise__c.
  • A custom field with a label of Description has an API name of Description__c.
  • A custom relationship field with a label of Items has an API name of Items__r.
In addition, spaces in labels are replaced with underscores in API names. For example, a custom field name of Employee Seniority has an API name of Employee_Seniority__c.

Finding Object and Field Names

To find out the names of standard objects and their fields for use in Apex, refer to the Object Reference for Salesforce and Force.com.
For custom objects, look up the object and field API names in your org. From Setup, enter Objects in the Quick Find box, then select Objects, and then click your object’s name.

Creating sObjects and Adding Fields

Before you can insert a Salesforce record, you must create it in memory first as an sObject. Like with any other object, sObjects are created with the new operator:
Account acct = new Account();
The API object name becomes the data type of the sObject variable in Apex. In this example, Account is the data type of the acct variable.
The account referenced by the acct variable is empty because we haven’t populated any of its fields yet. There are two ways to add fields: through the constructor or by using dot notation.
The fastest way to add fields is to specify them as name-value pairs inside the constructor. For example, this statement creates a new account sObject and populates its Name field with a string value.
Account acct = new Account(Name='Acme');
The Name field is the only required field for accounts, which means that it has to be populated before being able to insert a new record. However, you can populate other fields as well for the new record. This example adds also a phone number and the number of employees.
Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100);
Alternatively, you can use the dot notation to add fields to an sObject. The following is equivalent to the previous example, although it takes a few more lines of code.
Account acct = new Account();
acct.Name = 'Acme';
acct.Phone = '(415)555-1212';
acct.NumberOfEmployees = 100;

Working with the Generic sObject Data Type

Typically, you use the specific sObject data type, such as Account for a standard object or Book__c for a custom object called Book, when working with sObjects. However, when you don’t know the type of sObject your method is handling, you can use the generic sObject data type.
Variables that are declared with the generic sObject data type can reference any Salesforce record, whether it is a standard or custom object record.
This example shows how the generic sObject variable can be assigned to any Salesforce object: an account and a custom object called Book__c.
sObject sobj1 = new Account(Name='Trailhead');
sObject sobj2 = new Book__c(Name='Workbook 1');
In contrast, variables that are declared with the specific sObject data type can reference only the Salesforce records of the same type.

Casting Generic sObjects to Specific sObject Types

When you’re dealing with generic sObjects, you sometimes need to cast your sObject variable to a specific sObject type. One of the benefits of doing so is to be able to access fields using dot notation, which is not available on the generic sObject. Since sObject is a parent type for all specific sObject types, you can cast a generic sObject to a specific sObject. This example shows how to cast a generic sObject to Account.
// Cast a generic sObject to an Account
Account acct = (Account)myGenericSObject;
// Now, you can use the dot notation to access fields on Account
String name = acct.Name;
String phone = acct.Phone;
Unlike specific sObjects types, generic sObjects can be created only through the newSObject() method. Also, the fields of a generic sObject can be accessed only through the put() and get() methods.
In this unit, you’ve learned what sObjects are and how to use them. However, creating an sObject doesn’t persist it as a record in the database. To save the sObject as a record, and do other things with it, use the Data Manipulation Language (DML). To retrieve a record, use the Salesforce Object Query Language (SOQL). Check out later units to learn about DML and SOQL.

Manipulate Records with DML

Create and modify records in Salesforce by using the Data Manipulation Language, abbreviated as DML. DML provides a straightforward way to manage records by providing simple statements to insert, update, merge, delete, and restore records.
Because Apex is a data-focused language and is saved on the Force.com platform, it has direct access to your data in Salesforce. Unlike other programming languages that require additional setup to connect to data sources, with Apex DML, managing records is made easy! By calling DML statements, you can quickly perform operations on your Salesforce records.
This example adds the Acme account to Salesforce. An account sObject is created first and then passed as an argument to the insert statement, which persists the record in Salesforce.
// Create the account sObject 
Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100);
// Insert the account by using DML
insert acct;

DML Statements

The following DML statements are available.
  • insert
  • update
  • upsert
  • delete
  • undelete
  • merge
Each DML statement accepts either a single sObject or a list (or array) of sObjects. Operating on a list of sObjects is a more efficient way for processing records.
All those statements, except a couple, are familiar database operations. The upsert and merge statements are particular to Salesforce and can be quite handy.
The upsert DML operation creates new records and updates sObject records within a single statement, using a specified field to determine the presence of existing objects, or the ID field if no field is specified.
The merge statement merges up to three records of the same sObject type into one of the records, deleting the others, and re-parenting any related records.

ID Field Auto-Assigned to New Records

When inserting records, the system assigns an ID for each record. In addition to persisting the ID value in the database, the ID value is also autopopulated on the sObject variable that you used as an argument in the DML call.
This example shows how to get the ID on the sObject that corresponds to the inserted account.
// Create the account sObject 
Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100);
// Insert the account by using DML
insert acct;
// Get the new ID on the inserted sObject argument
ID acctID = acct.Id;
// Display this ID in the debug log
System.debug('ID = ' + acctID);
// Debug log result (the ID will be different in your case)
// DEBUG|ID = 001D000000JmKkeIAF
Because the sObject variable in the example contains the ID after the DML call, you can reuse this sObject variable to perform further DML operations, such as updates, as the system will be able to map the sObject variable to its corresponding record by matching the ID.
You can retrieve a record from the database to obtain its fields, including the ID field, but this can’t be done with DML. You’ll need to write a query by using SOQL. You’ll learn about SOQL in another unit.

Bulk DML

You can perform DML operations either on a single sObject, or in bulk on a list of sObjects. Performing bulk DML operations is the recommended way because it helps avoid hitting governor limits, such as the DML limit of 150 statements per Apex transaction. This limit is in place to ensure fair access to shared resources in the Force.com multitenant platform. Performing a DML operation on a list of sObjects counts as one DML statement for all sObjects in the list, as opposed to one statement for each sObject.
This example inserts contacts in bulk by inserting a list of contacts in one call. The sample then updates those contacts in bulk too.
  1. Execute this snippet in the Developer Console using Anonymous Apex.
  2. Inspect the contacts recently created in your org.
    Two of the contacts who are in the Finance department should have their titles populated with Financial analyst.

// Create a list of contacts

List<Contact> conList = new List<Contact> {
    new Contact(FirstName='Joe',LastName='Smith',Department='Finance'),
        new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'),
        new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'),
        new Contact(FirstName='Kim',LastName='Shain',Department='Education')};
            
// Bulk insert all contacts with one DML call
insert conList;

// List to hold the new contacts to update
List<Contact> listToUpdate = new List<Contact>();

// Iterate through the list and add a title only
//   if the department is Finance
for(Contact con : conList) {
    if (con.Department == 'Finance') {
        con.Title = 'Financial analyst';
        // Add updated contact sObject to the list.
        listToUpdate.add(con);
    }
}

// Bulk update all contacts with one DML call
update listToUpdate;

Upserting Records

If you have a list containing a mix of new and existing records, you can process insertions and updates to all records in the list by using the upsert statement. Upsert helps avoid the creation of duplicate records and can save you time as you don’t have to determine which records exist first.
The upsert statement matches the sObjects with existing records by comparing values of one field. If you don’t specify a field when calling this statement, the upsert statement uses the sObject’s ID to match the sObject with existing records in Salesforce. Alternatively, you can specify a field to use for matching. For custom objects, specify a custom field marked as external ID. For standard objects, you can specify any field that has the idLookup property set to true. For example, the Email field of Contact or User has the idLookup property set. To check a field’s property, see the Object Reference for Salesforce and Force.com.
Upsert Syntax
upsert sObject | sObject[]
upsert sObject | sObject[]​​ field
The optional field is a field token. For example, to specify the MyExternalID field, the statement is:
upsert sObjectList Account.Fields.MyExternalId;
Upsert uses the sObject record's primary key (the ID), an idLookup field, or an external ID field to determine whether it should create a new record or update an existing one:
  • If the key is not matched, a new object record is created.
  • If the key is matched once, the existing object record is updated.
  • If the key is matched multiple times, an error is generated and the object record is neither inserted or updated.
This example shows how upsert updates an existing contact record and inserts a new contact in one call. This upsert call updates the existing Josh contact and inserts a new contact, Kathy.
The upsert call uses the ID to match the first contact. The josh variable is being reused for the upsert call. This variable has already been populated with the record ID from the previous insert call, so the ID doesn’t need to be set explicitly in this example.
  1. Execute this snippet in the Execute Anonymous window of the Developer Console.
  2. Inspect all contacts in your org.

Your org will have only one Josh Kaplan record, not two, because the upsert operation found the existing record and updated it instead of creating a new contact record. One Kathy Brown contact record will be there too.
// Insert the Josh contact
Contact josh = new Contact(FirstName='Josh',LastName='Kaplan',Department='Finance');   
insert josh;
// Josh's record has been inserted
//   so the variable josh has now an ID
//   which will be used to match the records by upsert
josh.Description = 'Josh\'s record has been updated by the upsert operation.';
// Create the Kathy contact, but don't persist it in the database
Contact kathy = new Contact(FirstName='Kathy',LastName='Brown',Department='Technology');
// List to hold the new contacts to upsert
List<Contact> contacts = new List<Contact> { josh, kathy };
// Call upsert
upsert contacts;
// Result: Josh is updated and Kathy is created.
Alternatively, you can specify a field to be used for matching records. This example uses the Email field on Contact because it has idLookup property set. The example inserts the Jane Smith contact, and creates a second Contact sObject, populates it with the same email, then calls upsert to update the contact by using the email field for matching.
If insert was used in this example instead of upsert, a duplicate Jane Smith contact would have been inserted.
Execute this snippet in the Execute Anonymous window of the Developer Console.
Contact jane = new Contact(FirstName='Jane',
                         LastName='Smith',
                         Email='jane.smith@example.com',
                         Description='Contact of the day');
insert jane;

// 1. Upsert using an idLookup field
// Create a second sObject variable.
// This variable doesn’t have any ID set.
Contact jane2 = new Contact(FirstName='Jane',
                         LastName='Smith',  
                         Email='jane.smith@example.com',
                         Description='Prefers to be contacted by email.');
// Upsert the contact by using the idLookup field for matching.
upsert jane2 Contact.fields.Email;

// Verify that the contact has been updated
System.assertEquals('Prefers to be contacted by email.',
                   [SELECT Description FROM Contact WHERE Id=:jane.Id].Description);
Inspect all contacts in your org. Your org will have only one Jane Smith contact with the updated description.

Deleting Records

You can delete persisted records using the delete statement. Deleted records aren’t deleted permanently from Force.com, but they’re placed in the Recycle Bin for 15 days from where they can be restored.
This example shows how to delete all contacts whose last name is Smith. If you’ve run the sample for bulk DML, your org should already have two contacts with the last name of Smith. Execute this snippet in the Developer Console using Anonymous Apex, and then verify that there are no contacts with the last name Smith anymore.
Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith']; 
delete contactsDel;

DML Statement Exceptions

If a DML operation fails, it returns an exception of type DmlException. You can catch exceptions in your code to handle error conditions.
This example produces a DmlException because it attempts to insert an account without the required Name field. The exception is caught in the catch block.
try {
    // This causes an exception because 
    //   the required Name field is not provided.
    Account acct = new Account();
    // Insert the account 
    insert acct;
} catch (DmlException e) {
    System.debug('A DML exception has occurred: ' +
                e.getMessage());
}

Database Methods

Apex contains the built-in Database class, which provides methods that perform DML operations and mirror the DML statement counterparts.
These Database methods are static and are called on the class name.
  • Database.insert()
  • Database.update()
  • Database.upsert()
  • Database.delete()
  • Database.undelete()
  • Database.merge()
Unlike DML statements, Database methods have an optional allOrNone parameter that allows you to specify whether the operation should partially succeed. When this parameter is set to false, if errors occur on a partial set of records, the successful records will be committed and errors will be returned for the failed records. Also, no exceptions are thrown with the partial success option.
This is how you call the insert method with the allOrNone set to false.
Database.insert(recordList, false);
The Database methods return result objects containing success or failure information for each record. For example, insert and update operations each return an array of Database.SaveResult objects.
Database.SaveResult[] results = Database.insert(recordList, false);
Upsert returns Database.UpsertResult objects, and delete returns Database.DeleteResult objects.
By default, the allOrNone parameter is true, which means that the Database method behaves like its DML statement counterpart and will throw an exception if a failure is encountered.
The following two statements are equivalent to the insert recordList; statement.
Database.insert(recordList);
And:
Database.insert(recordList, true);
In addition to these methods, the Database class contains methods that aren’t provided as DML statements. For example, methods used for transaction control and rollback, for emptying the Recycle Bin, and methods related to SOQL queries. You’ll learn about SOQL in another unit.

Example: Inserting Records with Partial Success

Let’s take a look at an example that uses the Database methods. This example is based on the bulk DML example, but replaces the DML statement with a Database method. The Database.insert() method is called with the partial success option. One contact in the list doesn’t have any fields on purpose and will cause an error because the contact can’t be saved without the required LastName field. Three contacts are committed and the contact without any fields generates an error. The last part of this example iterates through the returned results and writes debug messages to the debug log.
  1. Execute this example in the Execute Anonymous window of the Developer Console.
  2. Verify the debug messages (use the DEBUG keyword for the filter).
    One failure should be reported and three contacts should have been inserted.
// Create a list of contacts
List<Contact> conList = new List<Contact> {
        new Contact(FirstName='Joe',LastName='Smith',Department='Finance'),
        new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'),
        new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'),
        new Contact()};
            
// Bulk insert all contacts with one DML call
Database.SaveResult[] srList = Database.insert(conList, false);

// Iterate through each returned result
for (Database.SaveResult sr : srList) {
    if (sr.isSuccess()) {
        // Operation was successful, so get the ID of the record that was processed
        System.debug('Successfully inserted contact. Contact ID: ' + sr.getId());
    } else {
        // Operation failed, so get all errors
        for(Database.Error err : sr.getErrors()) {
            System.debug('The following error has occurred.');
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Contact fields that affected this error: ' + err.getFields());
}
    }
}

Should You Use DML Statements or Database Methods?

  • Use DML statements if you want any error that occurs during bulk DML processing to be thrown as an Apex exception that immediately interrupts control flow (by using try. . .catch blocks). This behavior is similar to the way exceptions are handled in most database procedural languages.
  • Use Database class methods if you want to allow partial success of a bulk DML operation—if a record fails, the remainder of the DML operation can still succeed. Your application can then inspect the rejected records and possibly retry the operation. When using this form, you can write code that never throws DML exception errors. Instead, your code can use the appropriate results array to judge success or failure. Note that Database methods also include a syntax that supports thrown exceptions, similar to DML statements.

Working with Related Records

Create and manage records that are related to each other through relationships.

Inserting Related Records

You can insert records related to existing records if a relationship has already been defined between the two objects, such as a lookup or master-detail relationship. A record is associated with a related record through a foreign key ID. For example, if inserting a new contact, you can specify the contact's related account record by setting the value of the AccountId field.
This example shows how to add a contact to an account (the related record) by setting the AccountId field on the contact. Contact and Account are linked through a lookup relationship.
  1. Execute this snippet in the Anonymous Apex window of the Developer Console.
  2. Inspect the contacts in your org.
    A new account (SFDC Account) has been created and has the Mario Ruiz contact in the account’s Contacts related list.
Account acct = new Account(Name='SFDC Account');
insert acct;

// Once the account is inserted, the sObject will be 
// populated with an ID.
// Get this ID.
ID acctID = acct.ID;

// Add a contact to this account.
Contact mario = new Contact(
    FirstName='Mario',
    LastName='Ruiz',
    Phone='415.555.1212',
    AccountId=acctID);
insert mario;

Updating Related Records

Fields on related records can't be updated with the same call to the DML operation and require a separate DML call. For example, if inserting a new contact, you can specify the contact's related account record by setting the value of the AccountId field. However, you can't change the account's name without updating the account itself with a separate DML call. Similarly, when updating a contact, if you also want to update the contact’s related account, you must make two DML calls. The following example updates a contact and its related account using two updatestatements.
// Query for the contact, which has been associated with an account.
Contact queriedContact = [SELECT Account.Name 
                          FROM Contact 
                          WHERE FirstName = 'Mario' AND LastName='Ruiz'
                          LIMIT 1];

// Update the contact's phone number
queriedContact.Phone = '(415)555-1213';

// Update the related account industry
queriedContact.Account.Industry = 'Technology';

// Make two separate calls 
// 1. This call is to update the contact's phone.
update queriedContact;
// 2. This call is to update the related account's Industry field.
update queriedContact.Account; 

Deleting Related Records

The delete operation supports cascading deletions. If you delete a parent object, you delete its children automatically, as long as each child record can be deleted.
For example, deleting the account you created earlier (SFDC Account) will delete its related contact too.
  1. Execute this snippet in the Anonymous Apex window of the Developer Console.
  2. Check the accounts and contacts in your org.
You’ll see that both the account and its related contact were deleted.

Account[] queriedAccounts = [SELECT Id FROM Account WHERE Name='SFDC Account'];
delete queriedAccounts;

About Transactions

DML operations execute within a transaction. All DML operations in a transaction either complete successfully, or if an error occurs in one operation, the entire transaction is rolled back and no data is committed to the database. The boundary of a transaction can be a trigger, a class method, an anonymous block of code, an Apex page, or a custom Web service method. For example, if a trigger or class creates two accounts and updates one contact, and the contact update fails because of a validation rule failure, the entire transaction rolls back and none of the accounts are persisted in Salesforce.

Create a method for inserting accounts.

To pass this challenge, create an Apex class that inserts a new account named after an incoming parameter. If the account is successfully inserted, the method should return the account record. If a DML exception occurs, the method should return null.
  • The Apex class must be called 'AccountHandler' and be in the public scope.
  • The Apex class must have a public static method called 'insertNewAccount'.
  • The 'insertNewAccount' method must accept an incoming string as a parameter, name the account after the parameter, insert it into the system and then return the account record.
  • The 'insertNewAccount' method must also accept an empty string, catch the failed DML and return null.

public class AccountHandler {

//Public Class
    public static account insertNewAccount (String AcName){
    //Public Method    
        try{
            //Try Block
            Account acct = new Account(name=AcName);
            insert acct;
            System.debug('Account '+AcName+' created');
            return acct;
        }//Close Try Block
        catch(dmlException e){
            //Catch Block
            System.debug('A DML exception has occurred: ' + e.getMessage());
            return null;
        }//Close Catch Block
    }//Close Public Method
}//Close Public Class

Execute the above code in Developer Console's Execute Anonymous Code window as below -

AccountHandler.insertNewAccount('Test New Account-2');

OR

AccountHandler.insertNewAccount('');

6 comments:

  1. very informative blog and useful article thank you for sharing with us , keep posting learn more aboutsalesforce training salesforce Online Training

    ReplyDelete
  2. By leveraging its Java-like syntax and stored procedure functionality, developers can create robust and efficient solutions that streamline their workflow and enhance the overall user experience. boat rental abu dhabi

    ReplyDelete
  3. Apex empowers developers to create robust and dynamic solutions that enhance the overall user experience. Thanks for sharing this informative post! boats for sale abu dhabi

    ReplyDelete
  4. Thanks for the valuable information on biohazard bags! If you're searching for a reliable Biohazard bag Supplier in Delhi I recommend checking out Singhal Industries. They offer a wide range of high-quality biohazard bags designed for safe and effective waste management. Their products meet stringent safety standards and are known for their durability and performance. With their excellent customer service and commitment to quality, Singhal Industries is a top choice for anyone in need of biohazard bags in Delhi.

    ReplyDelete
  5. Cloud Solutions enables organizations to implement flexible and secure infrastructures that optimize operational efficiency. I truly appreciate you sharing this valuable information. Cisco distributors in dubai

    ReplyDelete
  6. Apex is Salesforce's programming language used for back-end development, allowing developers HostingRaja to execute flow and transaction control statements on the Salesforce platform and interact with the database through SOQL and DML.






    ReplyDelete

Lightning Inter-Component Communication Patterns

Lightning Inter-Component Communication Patterns If you’re comfortable with how a Lightning Component works and want to build producti...