,

Triggers

As you learned in the last chapter, Apex code can be used in classes or in triggers. A trigger is a block of Apex code that executes in response to a particular type of change in a record’s data.

Triggers are directly linked to the records in an object so that a trigger fires whenever a record is affected—whether that record is accessed by a standard Force Platform page, a Visualforce page, or through the Web Services API. Once you define logic in a trigger, you can be sure that logic is always executed in response to the appropriate type of change in the records for its object.

Voice of the Developer

Triggers can be deactivated, this can be useful if you want to manage data (loading test or sample data via Data Loader for example) and don’t want the trigger validation to get in the way.


Trigger options

When you define a trigger, you specify that the trigger comes either before or after a particular database event. These database events are inserting a record, updating a record, or deleting a record. In addition, you define a trigger that fires after a user undeletes a particular record.

The trigger options are defined as part of the trigger specification, as follows:

trigger <trigger_name> on <object_name> (<trigger_events>) {
 code_block;
 }

A trigger executes once for each database action that causes the trigger events for the trigger, such as an insert, update, or delete. The trigger operates on the set of records sent with a data manipulation command, discussed later in this chapter. You can define multiple triggers for each object, or you can specify more than one trigger event, such as in the following code fragment:

trigger beforeWrite on Position (before insert, before update) {
 code_block;
 }

Normally, you only combine multiple trigger events in the same trigger if all these events require all or some of the same logic.

You use trigger context variables to determine which action has spawned the execution of the trigger.

Tip

Remember that the standard save() operation executes all appropriate database actions, which could include insert, update, or delete. In addition, you can call an upsert operation, which will be discussed later in this chapter.


Trigger Context Variables

Every trigger supports a set of variables that reflect the current context of the trigger. These variables fall into three main areas:

  • Execution context variables- These variables represent a Boolean value that describes whether the current execution of the trigger is fired by a particular event. The execution context variables include isInsert, isUpdate, isDelete, isBefore, isAfter and isUndelete.

  • Record context variables- These variables give you access to the actual records affected by the trigger. The four record context variables are new, old, newMap and oldMap. Each of these variables is an array since all data manipulation in Apex is done in bulk. The new and old variables represent an array of records, while the newMap and oldMap represent maps with the key being the ID of the record and the value being the record itself.

    All of these record context variables are not available in all triggers, as shown in the table that follows:

    Table 9. Trigger context variables
    ActionTimingNewOld
    InsertBeforeCan be modified (newMap not available)Not available
     AfterCan be readNot available
    UpdateBeforeCan be readCan be read
     AfterCan be readCan be read
    DeleteBeforeNot availableCan be read
     AfterNot availableCan be read

    For instance, for an insert operation, you can add records to the trigger.new[] array in a before trigger, and read the records that are inserted in the same array in an after trigger. For an update trigger, the old and new arrays show the before and after values for the record, respectively. The trigger.old[] array for a delete action shows the records that will be or have been deleted, depending on whether the variable is accessed in a before or after trigger.

  • Other trigger context variables – Triggers also give access to the size variable for all trigger events, which represents the number of records in the trigger invocation.

Order of execution

Programming is an exacting science, one where small differences can produce different logical effects. If you have been reading this book from the beginning, you have come across a number of places where the Force Platform imposes some type of logic on data, including data type specification, validation rules, workflow, and triggers. The following list explains the order in which these logical operations are executed once a record is saved.

  1. The original record loads from the database or initializes for an insert operation.

  2. The new values load from the incoming request and overwrite the old values in the record buffer. The old values are saved in the old context variable for update triggers.

  3. Before triggers run.

  4. All system validation rules run, including required field checking and user-defined validation rules.

  5. The record is saved to the database, but the record is not committed.

  6. After triggers run.

  7. Assignment rules and auto-response rules run, which are typically created as part of extensions to the SalesForce Platform application

  8. Workflow rules execute. If field updates are specified, the record updates again, and before and after triggers for the update fire.

  9. Escalation rules execute, which are typically created as part of extensions to SalesForce Platform applications

  10. All data manipulation operations are committed to the database.


Exceptions in Triggers

Triggers can be used to take actions when records are inserted, modified or deleted. There may be times when you want to use a trigger to stop a particular data operation from taking place.

You can implement this by using database exceptions. The addError() method adds an exception to the current record, or a field within the current record, in a before trigger. When the Force Platform platform goes to perform the data manipulation action, the action does not proceed if any of the records to be manipulated are marked with an addError() method. The addError() result causes a DmlException and the DML operation to be rolled back.

The feedback supplied in the event of a trigger exception depends on whether the DmlException is caught by the Apex code in the trigger. If the exception is caught, the trigger continues any processing to see if there are any other exceptions in the group of records affected by the trigger. If the exception is not caught, a single exception causes all processing to stop and for all records to be marked with an error.

Creating a Trigger

You have acquired the basic knowledge you need to use triggers, so it is time to define one for yourself. Since you have not yet explored the Salesforce Object Query Language (SOQL), which is used to retrieve records from objects in the Force Platform database, you can implement a simple trigger that throws a trigger exception in response to an invalid Job Application.

Different positions throughout Universal Containers have different levels of strictness about education requirements. Although reaching a certain level of educational attainment is always seen as a good thing, some positions absolutely require a specific level of education from any applicant.

The scripts mentioned at the start of this chapter added a new field to the Position record, a checkbox, Reject_Undereducated__c, that indicates whether Job Applications are rejected if the Candidate does not have the required level of education. Your first trigger checks to see if that requirement is specified, and then checks to see if the Candidate has the required level of education.

1.
Go to Setup Create Objects Job Application.

2.
Click on New in the Triggers section to bring up the page shown below.



Figure 186. Creating a trigger


3.
The template for the trigger gives you the basic syntactical structure of your trigger. With your knowledge of Apex, add in the following specification:

trigger rejectUndereducatedTrigger on Job_Application__c (
  before insert, before update) {
 }

The new code gives the trigger a name and specifies that the trigger runs before a Job Application record is either inserted or changed.

4.
The next step is to add the following for loop to iterate through the array of new records:

trigger rejectUndereducatedTrigger on Job_Application__c (
  before insert, before update) {
    for (Job_Application__c JA : trigger.new){
            }
    }
}

This loop is a SOQL for loop that was mentioned in the last chapter. The loop iterates through the collection of records in the trigger.new array, which will contain any records either inserted or updated.

5.
The next step is to retrieve the value of the Reject_Undereducated__c checkbox into the trigger, which you do with the highlighted line of code, which uses a simple SOQL statement. You will be formally introduced to SOQL in the following section.

trigger rejectUndereducatedTrigger on Job_Application__c (
before insert, before update) {
    for (Job_Application__c JA : trigger.new){
        Position__C getBack = [select
								reject_undereducated__c from
								position__c where ID = :JA.position__c];
    }
}

Why do you have to explicitly retrieve the Position record that is related to the Job Application record that fired the trigger? The values of related records are not available in triggers, for good reason. A record can be related to many other records in many other objects, and retrieving all of them whenever a trigger is fired might result in excessive overhead.

Optimizing trigger code

The code shown in this trigger is used as an example, to help you to understand how to write a trigger. However, this code has one potential performance issue built into its structure. Remember, trigger code is fired implicitly on a set of records that are submitted. In the code example above, you are properly iterating through the set of records in the trigger.new collection. However, you are making an individual SOQL call to retrieve the value of the Reject_Undereducated__c field for each record. If the trigger.new collection contained 100 records, you would call the SOQL statement 100 times.

Another way to implement this trigger is to select all the relevant Position__c records into a set at the start of the trigger, and then use the objects in the map to locally retrieve the value for the Reject_Undereducated__c field, as with the following code:

trigger rejectUndereducatedTrigger on Job_Application__c (
before insert, before update) {
    List<String> positions = new List<String>;
    for (Job_Application__c JA : trigger.new){
        positions.add(JA.Position__c);
        }
    List<Position__c> rejections = [select
        reject_undereducated__c from
        position__c where ID in :positions];
        }
}

The in operator checks to see if the value is contained in a list of values, as you will see in the next section. You would then use the same index to examine the value of reject_undereducated__c and the value of the candidate_qualified__c field on the Job Application record.

The net result of this code will be to execute a single SOQL statement, regardless of the number of Job Applications passed to the trigger.


6.
The next step for this trigger is to add the logic that checks to see if the Position record requires a certain level of education, and if the Candidate possesses the level of education required for the position. Add the highlighted code shown below to your trigger.

trigger rejectUndereducatedTrigger on Job_Application__c (
before insert, before update) {
    for (Job_Application__c JA : trigger.new){
        Position__C getBack = [select
          reject_undereducated__c from
          position__c where ID = :JA.position__c];
        if ( getBack.reject_undereducated__c &&
								(JA.candidate_qualified__c == 'Not qualified')) {
								}
    }
}

The double ampersand sign (&&) represents an AND condition. The column reference uses a relationship to identify fields on the Position and Candidate records that are parents of this Job Application record, syntax you will learn more about in the next section on SOQL.

7.
The final step is when you actually add an error to a Job Application record that qualifies to be rejected, with the last highlighted line of code.

trigger rejectUndereducatedTrigger on Job_Application__c (
before insert, before update) {
    for (Job_Application__c JA : trigger.new){
        Position__C getBack = [select
          reject_undereducated__c from
          position__c where ID = :JA.position__c];
        if ( getBack.reject_undereducated__c &&
          (JA.candidate_qualified__c == 'Not qualified')) {
            JA.addError('You are not allowed to apply
								without proper educational requirements.'),,
              }
        }
}

If a Job Application record is about to be inserted or updated with values that fail this logical test, the addError() method flags the record and associates the text message argument with that error.

8.
Click Save to save the new trigger and return to the detail page for the trigger.

By default, triggers are active when saved. You can make a trigger inactive with a checkbox in the edit page for the trigger or by editing the metadata for the trigger in the Force Platform IDE.

You can easily see the results of this trigger in your application.

1.
Go to the Positions tab and select a position.

2.
Make sure that the checkbox labeled ‘Reject undereducated’ is checked and note the educational level.

3.
Click New Job Application to add a job application.

4.
Click the lookup icon to select a candidate for the job.

The lookup results page layout has had the educational attainment of the candidate added to it in the script file you ran at the start of this chapter to make it easier for you to select a candidate.

5.
Select a candidate who does not have the proper education.

6.
Click Save, which should bring up the page shown below.

Figure 187. Your trigger at work


The figure above shows that the save action has been rejected, with the error message displayed at the top of the page.

With this trigger, you have guaranteed that no candidate whose educational achievement does not meet the requirements for a particular position is allowed to apply for that position. This trigger implements this logic whenever a Job Application record is written to the Force Platform object.

Now that you understand the basics of triggers, you can move on to learning about the languages used to access data in your Force Platform application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.51.157