Tuesday, 31 May 2011

Test Method for Trigger

Hi,

I just saw a problem on develoer community. I would like to share it with you.


Problem : I need help with the test method of this trigger, can someone please help me with the code, the trigger works but do not know how to create the test methods to deploy it to production:


The trigger is:
trigger CopyAttachments on MileStone__c(after insert)
{
Attachment[] attList = [select id, name, body from Attachment where ParentId = :Trigger.new[0].Opportunity__c];
Attachment[] insertAttList = new Attachment[]{};
 
         for(Attachment a: attList)
         {
               Attachment att = new Attachment(name = a.name, body = a.body, parentid = Trigger.new[0].id);
               insertAttList.add(att);
         }
       if(insertAttList.size() > 0)
       {
            insert insertAttList;
       }
Solution :
@isTest
private class TestCopyAttachments 
    { 
        //
        // This testMethod tests CopyAttachments triger
        // 
        public static testmethod void testCopyAttachments()
            {
                       
                //Insert a new instance of Oppurtunity Object with test values 
                Opportunity opr = new Opportunity(Name = 'Test' , StageName = 'TestStag' , CloseDate = Date.today());
                insert opr;
                
                //Insert a list of Oppurtunity Object with test values 
                List<Attachment> listAtt = new List<Attachment>();
                
                for(Integer i = 0; i < 5 ; i++)
                    { 
                        Attachment att = new Attachment(Name = 'TestAttachement', ParentId = opr.id , Body = Blob.valueOf('Test Attachment'));
                        listAtt.add(att);
                    }
                
                insert listAtt;
                
                test.startTest();
                
                MileStone__c mileStone = new MileStone__c(Opportunity__c = opr.id);
                insert mileStone;
                List<Attachment> listAttCopied = [Select id From Attachment where ParentId =: mileStone.id];
                system.assertEquals(listAttCopied.size() , listAtt.size());
                
                test.stopTest();
            }
    }

URL for issue in community

Friday, 27 May 2011

Summer 11 Features

Hi,

I want to share some new enactments and feature thats coming our way in picked from summer 11 release notes.

1) Package Upload Monitoring
Available in: All Editions

As of Summer ’11, ISVs can now track package uploads directly and view any failures during the upload process. Email notification is no longer required.There are new tabs to navigate to the package detail page and new real-time upload indicators
on the package and package version pages. You can follow an upload step by step, including individual Apex test runs.

2)Half-Up Rounding for All Numeric Fields
Available in: All Editions

As of Summer '11, all numeric fields use the round half up tie-breaking rule. For example, 12.345 becomes 12.35 and −12.345
becomes −12.35.


3)Limit Updates for Fields on Custom Objects, Sharing Rules, and Rich Text Area and Long Text Area Fields
Available in: Professional, Enterprise, Unlimited, Developer, and Database.com Editions

In Summer '11, the limit for the maximum number of fields on a custom object has been raised from 500 to 800 fields per object in Unlimited Edition. The total number of sharing rules per object increases from 100 to 300 in Professional, Enterprise, Unlimited, Developer and Database.com Editions.There are no longer limits to the number of rich text area and long text area fields that an object can contain, although your Edition's limit for the total number of custom fields allowed on an object, regardless of field type, still applies. Now, each object can contain a total of 1.6 million characters across long text area and rich text area fields. The default character limit for long text area and rich text area fields is 32,000 characters. A long text area or rich text area field needs to contain at least 256 characters. This update is for all Editions except Database.com


4)Quick Find Available in Setup
Available in: All Editions

In Summer '11, the sidebar in setup includes a search box for browsing and quickly finding setup tools. In the left pane of any setup page, you can:
• Type the first few characters of a setting name in the Quick Find box. As you type, items that match your search terms appear in the menu. Click an item in the list to go to its setup page. For example, to quickly find the user profiles page, type prof in the Quick Find box.
• Click Expand All to open all setup menus. If you have typed anything in the Quick Find box, only the menus with matching items are expanded.

Regards

Thursday, 26 May 2011

Summer 11 Field Sets

Hi All,

Dynamic binding has been one of the most popular new feature in Salesforce Spring 11 release. In summer 11 Field Sets configuration have a different UI then earlier and has attributes associated with it. Ealier configuration was done using there different Boxes now it is like page layout editor where fields can be drag and drop.


 This is how field set configuration screen looks. Configuring it similar to configuring page layouts.

In Summer '11 Some more additional properties are also included in Field Sets now.

1)Required : In the field set it can be mentioned then when this field will be rendered on any Visualforce page it will be required. Again doing it similar like we make any field required in page layouts. Click to properties for any field in "In the Field Set",  there you will see a Check Box field "Required",  set this to true and click Ok and save this field set.

2)You can span a field into a field set that references multiple objects. The total number of cross object spans within the In the Field Set is 25.

Idea for future release :
Blank Space Option for Field Set Editor
Please promote if you feel it will be good addition.

Regards


Wednesday, 25 May 2011

Writing Apex Trigger : Issues and Solutions ( Cyclic Trigger )

Hi All,

Some times we have a situation where trigger on a event of one object fires another trigger and logic in that trigger again fires first trigger. These situations are called cyclic triggers.
Ex :


trigger Trigger1 on Account (after update) 
    {
        
        for(Account acc : Trigger.New)
            {   
                //Trigger Action Logic
                List<Contact> listCon = [Select Fax from Contact where AccountId =: acc.id];      
                for(Contact con : listCon)
                    {
                        con.Fax = acc.Fax;
                    }
                update listCon;    
           
            }
    }
Another trigger on Contact object update is written like :


trigger Trigger2 on Contact (after update) 
    {
        
        for(Contact con  : Trigger.New)
            {   
                //Trigger Action Logic
                List<Account> accList = [Select Phone from Account where id =: con.AccountId];      
                for(Account acc : accList)
                    {
                        acc.Phone = con.Phone;
                    }
                update accList;    
           
            }
    }

In Above example event in Trigger1 invokes Trigger2 and event in Trigger2 again invokes Trigger1.

Solution : If we use entry criteria as explained in earlier post then cyclic trigger problem will be solved.
Writing Apex Trigger : Issues and Solutions ( Entry Criteria)


Tuesday, 24 May 2011

Writing Apex Trigger : Issues and Solutions ( Bulk Upload )

Hi All,

I have been facing issue of exceeding limit even though applying every possible optimizing tech. that we discussed in earlier posts. This case is more often if not always is trigger invocation on bulk upload of records. Now to avoid such situations use a Static Variable on the start of trigger. And on action of bulk upload set this static variable to false.
Create a Class with Static Variable
public class Constants
    {
         //Constant to block execution of trigger
         public static Boolean runTrigger = true;
    }
trigger <name> on Account (<events>) 
    {
        if(Constants.runTrigger)
            {
                //logic to be executed by trigger
            }
    }
Now we should set static variable to false
public class BulkUpdateClass
    {
         //Method to do trigger event on bulk of records
         public void triggerBulkUpdate()
               {
                    //Set static variable to false
                    Constants.runTrigger = false;

                    //Bulk Update Action Logic
               }
    }

By this we can stop execution of trigger for bulk of records

Regards

Monday, 23 May 2011

Writing Apex Trigger : Issues and Solutions ( Entry Criteria)

Hi All,

Here are some issues that we face using triggers

1) Triggers Gets executed every time when the sObject gets inserted or updated , even though we don't want so and want our trigger gets executed only when any condition as per our requirement gets satisfied.
Solution : The condition of your requirement is the entry criteria for your trigger and that entry criteria should checked before executing any logic in the trigger.
Ex : We need to copy account fax field to fax field of contact records for that account when account gets updated
   
trigger TriggerWithoutEntryCriteria on Account (after update) 
    {
        
        for(Account acc : Trigger.New)
            {   
                //Trigger Action Logic
                List<Contact> listCon = [Select Fax from Contact where AccountId =: acc.id];      
                for(Contact con : listCon)
                    {
                        con.Fax = acc.Fax;
                    }
                update listCon;    
           
            }
    }

Now this trigger does not have entry criteria and will execute every time when account record gets updated regardless the fax field is updated or not. Now we will add entry criteria to this trigger.
trigger TriggerWithEntryCriteria on Account (after update) 
    {
        Integer index = 0;       
        for(Account acc : Trigger.New)
            {
                //Check entry criteria
                if(acc.Fax != Trigger.Old[index].Fax)                
                    {
                         //Trigger Action Logic
                         List<Contact> listCon = [Select Fax from Contact where AccountId =: acc.id];      
                         for(Contact con : listCon)
                             {
                                 con.Fax = acc.Fax;
                             }
                         update listCon;    
                    }
                index++;
            }
    }
After adding the entry criteria we have made our Trigger Action Logic to execute only when Fax field of account is updated.
In above example SOQL and DML are used in for loop that should also be removed using collections as discussed in earlier posts.

Regards

Sunday, 22 May 2011

Writing Apex Trigger : Order of Execution ( Structure your trigger )

Hi All,

In this post we will discuss how does a trigger gets executed. This is very important to know to structure the trigger when there are many triggers on a sObject Type. Lets take a example of a simple class with a static varibale triggerEntryCount
public class Constants
    {
         //Constant to keep track of entry in trigger
         public static Integer triggerEntryCount = 0;
        
    }

A trigger is written
trigger Test_TriggerEntry on Account ( after update , after insert , before insert , 
before update , after delete , before delete ) 
    {
        Constants.triggerEntryCount = Constants.triggerEntryCount + 1;
    }

Now we will write a test class
private static testmethod void testTriggerEntry()
            {
                
                List<Account> listAccInsert =  new List<Account>();
                
                Account a = New Account(Name = 'TestAccountA');
                listAccInsert.add(a);
                Account b = New Account(Name = 'TestAccountB');
                listAccInsert.add(b);
                // insert list of accounts
                insert listAccInsert;
                system.debug('Trigger Entry Count : '+ Constants.triggerEntryCount); 
                
            } 

When we run the test class, system debug shows

Trigger Entry Count : 2
In this trigger entries were made for before insert and after insert.
Sequence for entry : before insert and after insert

Now we change test class a bit to check upsert event where two records are updated and one is inserted
private static testmethod void testTriggerEntry()
            {
                
                List&lt;Account&gt; listAccInsert =  new List&lt;Account&gt;();
                
                Account a = New Account(Name = 'TestAccountA');
                listAccInsert.add(a);
                Account b = New Account(Name = 'TestAccountB');
                listAccInsert.add(b);
                // insert list of accounts
                insert listAccInsert;
                

                //Initialize triger count to zero
                Constants.triggerEntryCount = 0;
                Contact c = new Contact( LastName = ' Test Contat ' , AccountId = a.id , Email =   
                'testTrigger@testMethod.com');
                insert c;
                
                System.debug(' ******** Start Debug ********* ');
                
                List<Account> listAccUpsert =  new List<Account>();
                a.Name = 'New Test Account A';
                b.Name = 'New Test Account B';
                listAccUpsert.add(a);
                listAccUpsert.add(b);
                
                Account a1 = New Account(Name = 'TestAccount');
                listAccUpsert.add(a1);

                //upsert list of accounts
                upsert listAccUpsert;
                system.debug('Trigger Entry Count : '+ Constants.triggerEntryCount);
                
            }
This time in system debug :
Trigger Entry Count : 4
Sequence for entry : Before Insert , After Insert , Before Update , After Update

Now if we have triggers on a sObject for all of these events in that case we need to structure our code in a way that only appropriate code gets executed in a trigger entry.

Structure trigger like this :
trigger Test_Trigger on Account ( after update , after insert , before insert , 
before update , after delete , before delete ) 
    {
        
        if (Trigger.isBefore)
            {
               
                if (Trigger.isInsert)
                    {     
                        // Logic to be executed for Before Insert
                    }
                    
                if (Trigger.isupdate)
                    {   
                        // Logic to be executed for Before Update
                    }
                 
                 if (Trigger.isDelete)
                    {     
                        // Logic to be executed for Before Delete  
                    }
            }
            
        if (Trigger.isAfter)
            {
           
                if (Trigger.isInsert)
                    {     
                        // Logic to be executed for After Insert
                    }
                    
                if (Trigger.isupdate)
                    {   
                        // Logic to be executed for After Update  
                    }
                
                 if (Trigger.isDelete)
                    {     
                        // Logic to be executed for After Delete
                    }
            }    
            
        
    }

In case you have same trigger logic for more then one trigger context
1)Use trigger context variables with logical operator OR ( "||" )
Or
2)Create a method for the logic and use that in the all the contexts where you want it to execute

Regards

Saturday, 21 May 2011

Writing Apex Trigger : Order of Execution (Trigger Context Variable)

Hi All,

In Last post we discussed how can we optimiza SOQL and DML in our triggers. But there are cases where we do not use SOQL in loop still we face such issue. Following are the such cases
1) Bulk upload
2) Cyclic Trigger Invocation : When we have bigger triggers that have more then one SOQL and dml statements, again it might be posible that dml in one trigger invoke another trigger and again that trigger invoke some other.
3)Some time we have custom pages where we save more then one object in a single instance in that case triggers of all the object are also invoked in single instance.

Now to solve these issues we need to write triggers in a structured manner with taking care of order of execution of trigger.Before going ahead first we need to be familiar with some Trigger Context Variables

Variable

Description

 isInsert

Returns true if this trigger was fired due to an insert operation, from the Salesforce user
interface, Apex, or the API.

 isUpdate 


Returns true if this trigger was fired due to an update operation, from the Salesforce user
interface, Apex, or the API.

 isBefore

Returns true if this trigger was fired before any record was saved.

 isAfter 


Returns true if this trigger was fired after all records were saved.

 isUndelete

Returns true if this trigger was fired after a record is recovered from the Recycle Bin (that is,
after an undelete operation from the Salesforce user interface, Apex, or the API.)


Regards

Writing Apex Trigger : Save Limits in Trigger

Hi All,

If we do not write triggers in such a way where salesforce limits such as SOQL, dml statements etc are not optimized then you will always see errors like Too Many SOQL etc. Mainly that happens when we have any SOQL or dml in for loop(iteration). But there are cases where we do not use SOQL in loop still we face such issue. Following are the such cases
1) Bulk upload
2) When we have bigger triggers that have more then one SOQL and dml statements, again it might be posible that dml in one trigger invoke another trigger and again that trigger invoke some other.
3)Some time we have custom pages where we save more then one object in a single instance in that case triggers of all the object are also invoked in single instance.

So by this we know that optimizing a trigger to save limits is essential. Now To save limits we should always follows some basic practice :
In a trigger
1) No SOQL or dml in a loop

In this example SOQL and dml both are in loop so when ever this trigger will be fired with bulk of records then Limits will exceed.

trigger testReqTrigger on Account (after update) 
{
    for(Account acc : Trigger.New){
    List<Contact> listCon = [Select Fax from Contact where AccountId =: acc.id];        for(Contact con : listCon){
        con.Fax = acc.Fax;
        }
    update listCon;

    }

Solution :
trigger testReqTrigger on Account (after update) 
    {
        //Get all the contacts for all the accounts in one SOQL
        List< Contact > listCon = [Select Fax , AccountID from Contact where AccountId in: Trigger.New];
        system.debug('****** listContacts  :  '+ listCon ); 
        //Map with Key : Account Id and Value : List of contacts for that account 
        Map< ID , List< Contact > > map_AccID_ContactRecord = new Map< ID , List< Contact > >();
        List< Contact > tempListCon = new List< Contact >();
        //Fill the map
        for(Contact c : listCon)
            {
                if(map_AccID_ContactRecord.containsKey(c.AccountID)) 
                    {
                     
                        tempListCon = map_AccID_ContactRecord.get(c.AccountID);
                        tempListCon.add(c);
                        map_AccID_ContactRecord.put(c.AccountID , tempListCon); 
                    }
                else 
                    {
                        tempListCon = new List< Contact >();
                        tempListCon.add(c);
                        map_AccID_ContactRecord.put(c.AccountID , tempListCon);
                    }
            }
        //List of contacts that will be updated
        List< Contact > listConTBU = new List< Contact >();
        for(Account acc : Trigger.New)
            {
                //check account has list of contacts in map
                if(map_AccID_ContactRecord.containsKey(acc.id)) 
                    {
                       //Loop over the list of contacts
                       for(Contact con : map_AccID_ContactRecord.get(acc.id))
                          {
                              con.Fax = acc.Fax;
                              //Add contact that needed to be updated
                              listConTBU.add(con); 
                          }
                    }
            }
        
        //update list of all the contacts for all accounts
        update listConTBU;

    }


2)Only one SOQL and dml should be there for an object type
    Ex : We have to write a trigger for
           1) Contact Fax is not null  then copy account fax to contact fax field
           2) Contact Phone is not null then copy account phone to contact phone field
trigger testReqTrigger on Account (after update)
    {
        for(Account acc : Trigger.New)
            {
                List<Contact> listConForFaxUpdate = [Select Fax from Contact where Fax != null And AccountId =: acc.id];       
                for(Contact con : listConForFaxUpdate)
                    {
                         con.Fax = acc.Fax;
                    }
                   
                update listConForFaxUpdate;
               
                List<Contact> listConForPhoneUpdate = [Select Phone from Contact where Phone != null And AccountId =: acc.id];       
                for(Contact con : listConForPhoneUpdate )
                    {
                         con.Phone = acc.Phone;
                    }
                   
                update listConForPhoneUpdate;    
            }
          
    }
In above example Contact Object Type has two SOQL and dml, that is worng way of writing trigger

Solution : Query both fields in single SOQL

trigger testReqTrigger on Account (after update) 
    {
        for(Account acc : Trigger.New)
            {
                // Query for both Fax and Phone
                // List contains contact records which do not have both Fax or Phone as null
                List<Contact> listConForUpdate = [Select Fax , Phone from Contact where (Fax != null  OR Phone != null ) And AccountId =: acc.id];        
                for(Contact con : listConForUpdate)
                    {
                         if(con.Fax != null)
                             {
                                 con.Fax = acc.Fax;
                                 if(con.Phone != null)
                                     con.Phone = acc.Phone;
                             }
                         else
                             {
                                 con.Phone = acc.Phone;
                             }    
                    }
                update listConForUpdate;
            }
           
    }

In above example we have used SOQL in a loop that can be removed with our first problems solution.

So these two are the basic practice that we should do so triggers work appropriately with bulk data also. Now after covering this basic practice we will discuss some problems of complex triggers, cyclic triggers where one trigger invokes another and there solutions and order of execution of the trigger.

Regards

Saturday, 14 May 2011

Writing Apex Trigger : My First Trigger

Hi,

Before we write our first trigger let us discuss the basix syntax of a trigger and what are the database activities/events which fires a trigger.
Syntax :

trigger <name> on Account (<events>) {

}
Here
1. Name is the name of the trigger this is required to provide and has to be unique for the object on which trigger is written. By uniqueness I mean to say that no two triggers on the same object can have similar name.

2. Events are the database activities which fires a trigger, this again is required for a trigger. So by this we can say Trigger is Apex Code that gets executed before and after of these operations.

  • Insert : Before and After
  • Update : Before and After
  • Delete : Before and After
  • Merge : Not directly, but both insert and delete trigger get fired for winning and losing records.
  • Upsert : Not directly, but both insert and update trigger gets fired
  • Undelete : After


Requirement : Now lets take an example of a requirement that whenever an Account gets updated then Fax field of the account should be copied in the fax field of all the contacts those have reference of this account.

trigger testReqTrigger on Account (after update) {
    for(Account acc : Trigger.New){
    List<Contact> listCon = [Select Fax from Contact where AccountId =: acc.id];        for(Contact con : listCon){
        con.Fax = acc.Fax;
        }
    update listCon;

    }

}
In above example we have not written the trigger which will use resources in optimized way, we will discuss trigger optimization in detail later.

Regards

Writing Apex Trigger : Trigger vs Workflow

Hi All,

Triggers are very essential in any business logic. Triggers are fired when any event gets executed in database. These events can be insertion, update or deletion of rows in data tables in the data tables. In Apex triggers are fired when any DML statement gets executed that means a new record added, existing record updated or deleted. Triggers in salesforce triggers are extended form of workflows. They provide more complex logic to be added to any DML action. So before learning how to write an Apex trigger it is important to make a decision when to go for a trigger not for workflow.

Trigger vs Workflow

S. No. Trigger Workflow
1. Triggers can not be updated on production org after being created via a managed package. Actions in workflows can be edited,removed and new actions can be added
2. More complex logic can be added in the triggers like DML actions on other object than the object on which trigger is written Less Complex logic is supported
3. Trigger get fired on more actions like on insert , update , delete and undelete Workflow get fired on insert and update
4. You can decide excution of trigger whether it should be before or after the initiation action like ( on before insert trigger or on after update trigger) Workflow only gets executed after any insert or update

So by above comparison you may decide when to opt for a trigger over a workflow.


Regards

Friday, 13 May 2011

Salesforce made me a Better Programmer:


Hi All,



Salesforce made me a Better Programmer:
I started my career 5 years back with .Net. All my college projects were also in .Net. I am working on salesforce for last four years. When I started working on salesforce I was a bit afraid specially of governor limits.  But soon I realize that these limits are friend not foe.
Governor Limits Friend not Foe: When I faced too many SOQL, too many dml or to many query rows I thought why there are such limits. But when I started using collections for resolving them soon I realized these limits are for my help. Now it has become a general practice for me to take care of these limits. Now If I look back to my code that I developed in .Net applications I would definitely write efficient code to improve performance. Use of collections for performance is something I learned because of Governor Limits.  
Test Class Coverage is to make things easy: When we first time created a Managed package and did a runAll tset first time. We got around 75 test failures and 60% code coverage. Our initial thought was why is it necessary when we have already tested the functionality and QA has passed it. It took next 4-5 days to fix those test methods and improve code coverage. In those 5 days we not only changed the test methods but also changed our APEX Code as well as there were some issues those we missed to figure out in our testing. That was the first benefit that we discovered of test methods but It was just start. When we found that after any bug fix in regression testing or after any enhancement we just needed to run the test and we saved so much effort. Now it has become a practice for us that we like to follow to write test cases covering all scenarios. And let me tell you that when we see this “All Test Success” and Code Coverage 100% , It’s a great feeling.
There are so many other reasons that could be made here. My conclusion on all is that Limits in Salesforce has never stopped me from doing anything but have made me to think for a better way. And that is why I have started this blog to help the people if I can.

Blog Purpose : 


This blog is to share and discuss Salesforce knowledge, tricks, problems, solutions, findings, new release features. I invite you all to join this and share your knowledge with others and learn salesforce together.

Regards

Tweet