Wednesday 31 December 2014

Truncating Custom Objects


Truncating custom Object allows you to remove all of the object's records, while keeping the object and its metadata. When you truncate a custom Object Salesforce places a truncated object in the Deleted Object list for 15 days. It appears in deleted object list as objectname_trunc.

NOTE : During this time, the truncated object and its record continue to count against your org limits.

NOTE : Truncated Objects can not be restored to their original state.

Truncating object is a fast way to permanently remove all of the records from an object, while keeping object and it metadata intact for future use.

Lets play with truncation

I have created a custom object "TestObject" and inserted few records.

On object defination page I can not see "Truncate " button 



to enable Truncate go to Setup -> Customize -> User Interface and select "Enable Custom Object Truncate "



on saving it a new button "Truncate " started to appear on custom objects definition page.




Clicking on Truncate button will delete all the records present ( from recycle bin as well) and put the record in another object named as objectname_trunc in deleted object list.




Truncating is much faster than batch delete.

Important points
1. You can not truncate custom objects if they are referenced by another object through a look-up field.
2. You can not truncate custom objects if they are on Master side of a Master-Detail relationship.
3. You can not truncate custom objects if they contains geolocation field.
4. You can not truncate custom objects if they contains field marked as externalId.
5. Truncating custom object will remove custom object's history.
6. Truncating custom object erase all records currently in recycle bin.
7. Truncating object will erase related Tasks, Events, Notes, Attachments for each deleted record.

Salesforce preserves
1. Workflows, Actions, Triggers.
2. Sharing rules associates with custom object.
3. Validation Rules and Approval process.


Reference : Truncating Custom Objects Overview

Tuesday 30 December 2014

New Button in Look-up Window


When you create a new Look-Up or Master-Detail field on any custom object or on any standard object and then during look-up you see a New button clicking on it will allow you to create a new record on run from look-up window.

Before discussing more about it few important points to note :

1. This button is available only for Account and Contact.

New Button for Account Look-up



New Button for Contact Look-up



No New Button for Opportunity, same for other custom and standard objects



New Button for Master-Detail relationship with Account, same for Contact




2. Record created by clicking New button on look-up window will bypass validation rules.

If you want to remove this "New" button from lookup window then you can do it from Setup -> Customize -> User Interface and deselect "Show Quick Create " and save the settings.




after deselecting check the lookup window to confirm if New button is removed.



NOTE : Deselecting the check-box will disable Quick creation of Account, Contact and Opportunity from side panel.

Make Rich Text Field Mandatory Using Validation Rule


If you want to make field of data type Rich Text mandatory, what would you do?

One way to achieve this is by making field mandatory from page layout, that will work fine if you are creating records from salesforce UI but that won't work when you will upload data using Data-loader.



What will be the next approach, writing validation rule ? 
In validation rule you going to use ISNULL or ISBLANK ?

Lets try with ISNULL and ISBLANK one by one

1. ISNULL : Determine if expression is null (blank) and return TRUE if it is. If it contains value, this function returns FALSE.

create a validation rule and check ISNULL() for that rich text field like below snapshot.



in validation rule I have checked ISNULL(Rich_Text__c) and saved it. 
Now try to save the record without entering any value in Rich_Text__c field, validation rule won't work.

Why ISNULL didn't work?
According to Salesforce Text Fields are never null, so this function will always return FALSE.
Ok, then we should try with ISBLANK().

2. ISBLANK : Determines if an expression has a value and returns TRUE if it does not. If it contains a value this function will returns FALSE.

We will update validation rule from ISNULL to ISBLANK for rich text field like below snapshot.


validation rule : ISBLANK(Rich_Text__c)
Now try to save a record without entering any value in RIch_Text__c field, validation rule won't work in this case as well.
Salesforce doc says for text fields use ISBLANK, then why our validation rule is not working, Strange.

To make our validation rule to work we will use salesforce another function LEN()

3. LEN : returns the number of characters in specified test string
modify your validation to 
LEN( Rich_Text__c ) = 0


above validation will work


NOTE: above validation will work for text but won't work if you insert only
image and no text. 










Saturday 20 December 2014

Difference between SOQL and SOSL


SOQL stands for Salesforce Object Query Language
SOSL stands for Salesforce Object Search Language
SOQL can be used in apex triggers, apex classes
SOSL can not be used in apex triggers.

SOQL returns Integer or list of sObject
SOSL returns List of List of sObject

SOQL can be used for DML operations
SOSL can not be used for DML operations

Total no. of SOQL queries issued : 100
Total no. of SOSL queries issued : 20

Total no. of records retrieved by SOQL query : 50,000
Total no. of records retrieved by SOSL query : 2,000


Use SOQL when

1. you know in which objects or fields the data resides.
2. you want to retrieve data from single object or multiple objects that are related to one another.
3. you want to count number of records meeting the criteria in query.
4. you want to sort the result.
you want to retrieve data from number, date or checkbox fields.

Use SOSL when

1. you don't know in which object or field the data resides.
2. you want to retrieve data from single or multiple objects that may or may not relate to each other.

Saturday 13 December 2014

Rollup Summary for Lookup Field


Few days back requirement came across where there was a need to create a rollup summary field for objects which do not have Master-Detail relationship but lookup relationship, and we all know rollup summary field is only available for Master Detail so we left with no other option but to write Apex Code.

We have two objects LookupMaster__c and LookupChild__c having lookup relation.

  
We will write trigger on LookupChild__c for event after insert, after update, after delete.

trigger customRollup on LookupChild__c(after delete, after insert, after update){
    
    set<Id> masterIdSet = new set<Id>();
    
    if(trigger.isInsert) {
        for(LookupChild__c lookupRec : trigger.new) {
            masterIdSet.add(lookupRec.LookupMaster__c);
        }    
    } else if(trigger.isUpdate) {
        for(lookupChild__c lookupRec : trigger.new) {
            masterIdSet.add(lookupRec.LookupMaster__c);
        }
    } else if(trigger.isDelete){
        for(lookupChild__c lookupRec : trigger.old) {
            masterIdSet.add(lookupRec.LookupMaster__c);
        }
    } 
    
    if(masterIdSet.size() > 0) {
        customRollup rollUp = new customRollup ();
        rollUp.rollupAmount(masterIdSet);
    }
}

and will write an Controller to write logic for insert, delete and update.

public Class customRollup {
    
    public void rollupAmount(set<Id> masterIdSet) {
        Integer AmountVal = 0;
        
        list<LookupChild__c > childList = new list<LookupChild__c >();
        childList = [Select Id, Name, Amount__c, LookupMaster__c From LookupChild__c Where LookupMaster__c IN: masterIdSet];
        
        map<Id, Integer> masterChildMap = new map<Id, Integer>();
        
        for(LookupChild__c child : childList) {
            if(masterChildMap.containsKey(child.LookupMaster__c)) {
                AmountVal = masterChildMap.get(child.LookupMaster__c) + (Integer)child.Amount__c;
                masterChildMap.put(child.LookupMaster__c, AmountVal);
            } else {
                masterChildMap.put(child.LookupMaster__c, (Integer)child.Amount__c);
            }
        }
        
        list<LookupMaster__c> masterList = new list<lookupMaster__c>();
        LookupMaster__c m;
        for(Id master : masterChildMap.keySet()) {
            m = new LookupMaster__c();
            m.Id = master;
            m.Total_Amount__c = masterChildMap.get(master);
            masterList.add(m);
        }
        update masterList;
    }
}

after saving above code the Total_Amount__c field on LookupMaster__c object will get updated value every time its child record get inserted, updated or deleted. You can also implement the logic for undelete as well in above code.