+ Start a Discussion
KCBKCB 

Getting Child.Parent.GrandParent ID asNull

Here is the relationship of an custom object (all are Lookup relations)
A--> B --> C
A--> D
Trying To Achieve, if a new record is created in "D" then "C" Custom field need to capture "D" latest record Name in a custom field (latest_D_Name__c)

I have written below code, I tested with Bulk data as well its working fine
But i want this to optimize as much as possible and make it simple. any suggestion will be helpful

Question in my mind always popping up, Why am getting Null when am trying to pull A.ID (C.B__r.A__c) through "1st For Loop" directly.
If i find a way to pull the A.id from "1st For Loop" , then i can get rid of "2nd For Loop" */
 
trigger C_CustomObjTrigger on C_CustomObj  (Before Update) {  
     set<ID> B_idset = new set<ID>();
     set<ID> A_idset = new set<ID>();
     // Getting Parent ID of Object C (1st For Loop)
     for(C_CustomObj C : Trigger.new){
          if(C.B_CustomObj != null)
             B_idset.add(C.B_CustomObj);
     }  
     // Getting Grand Parent ID (2nd For Loop)
     for(B_CustomObj B: [SELECT NAME,id,A_CustomObj FROM B_CustomObj where id in:B_idset]){
          if(B.A_CustomObj != null)
             A_idset.add(B.A_CustomObj);
     }  
    // pulling Childs list for Grand Parent  
     List<D_CustomObj> D = [Select id,name,Date__c,Value__c From D_CustomObj where A_CustomObj in: A_idset
                                          Order By Date__c Desc];
    If(Trigger.IsBefore) {  
    for(C_CustomObj C_Update: trigger.new){                                           
        if(C_Update.Approved__c == False){
           //Update the Decision Object :Latest D to be caluculated                                  
            if(D.size()>0){
                C_Update.latest_D_Name__c = D[0].Name;
            }                   
        }
   }        
 }

 
Best Answer chosen by KCB
MSRMSR
Hi Chaitanya,

U can try this snippet in the 'before' event of the trigger to get whatever field from the grand parent to child.


// Get a list of all Parent Ids
Set<Id> parentIds = new Set<Id>();
for (child__c chld : trigger.new) { parentIds.add(chld.MyParent__c);
}
// Get a map of all Parents with field information
Map<Id, Parent__c> parentsById = new Map<Id, Parent__c>();
ParentsById.putAll([SELECT Id, MyParentfield1__c,MyParentfield2__c FROM Parent__c WHERE Id IN :parentIds]);
    for(child__c chld:trigger.new){
      chld.chldfield1__c=parentsById.get(chld.MyParent__c).MyParentfield1__c;                          chld.chldfield2__c=parentsById.get(chld.MyParent__c).MyParentfield2__c;
      }

If this works , mark it as answer so that others might benefit.

All Answers

Kalpesh_007Kalpesh_007
Trigger.new or Trigger.Old does not store any relationship data,you will need to Query for it as you have done in your example.

Thanks,
claperclaper

Try changing your trigger to After  Update; On the after update operation you do have access to the relationships :

trigger C_CustomObjTrigger on C_CustomObj  (after Update) {  
     set<ID> B_idset = new set<ID>();
     set<ID> A_idset = new set<ID>();
     // Getting Parent ID of Object C (1st For Loop)
     for(C_CustomObj C : Trigger.new){
          if(C.A_CustomObj__c != null)
             A_idset.add(C.A_CustomObj__r.Id);
     }  

    // pulling Childs list for Grand Parent  
     List<D_CustomObj> D = [Select id,name,Date__c,Value__c From D_CustomObj where A_CustomObj in: A_idset
                                          Order By Date__c Desc];
    If(Trigger.IsBefore) {  
    for(C_CustomObj C_Update: trigger.new){                                           
        if(C_Update.Approved__c == False){
           //Update the Decision Object :Latest D to be caluculated                                  
            if(D.size()>0){
                C_Update.latest_D_Name__c = D[0].Name;
            }                   
        }
   }        
 }
 

 

KCBKCB
Claper, I tried as you suggested, still am getting Null.

 
KCBKCB
Another idea i got is, Creating a Formula Field and calling that in the code.
claperclaper
Can you paste the trigger with the modifications you added?
claperclaper
trigger C_CustomObjTrigger on C_CustomObj  (after Update) {  
     set<ID> B_idset = new set<ID>();
     set<ID> A_idset = new set<ID>();
     // Getting Parent ID of Object C (1st For Loop)
     for(C_CustomObj C : Trigger.new){
          if(C.A_CustomObj__c != null)
             A_idset.add(C.A_CustomObj__r.Id);
     }  

    // pulling Childs list for Grand Parent  
     List<D_CustomObj> D = [Select id,name,Date__c,Value__c From D_CustomObj where A_CustomObj in: A_idset
                                          Order By Date__c Desc];
   //in the previous version this was if(Trigger.isBefore) and this should be if(Trigger.isAfter) now 
   If(Trigger.isAfter) {  
    for(C_CustomObj C_Update: trigger.new){                                           
        if(C_Update.Approved__c == False){
           //Update the Decision Object :Latest D to be caluculated                                  
            if(D.size()>0){
                C_Update.latest_D_Name__c = D[0].Name;
            }                   
        }
   }        
 }
the code above has a modification, before the if statment was "if(Trigger.isBefore)" not it should be if(Trigger.IsAfter) try that.
 
KCBKCB
I took all the other code out and checking the ID value only

trigger C_CustomObjTrigger on C_CustomObj   (After Update) {
     set<ID> A_idset = new set<ID>();   
       for(C_CustomObj C  : Trigger.new){
          if(C.B_CustomObj__r.A_CustomObj__c != null)
              A_idset.add(C.B_CustomObj__r.A_CustomObj__r.id);
         System.debug('Test' +C.B_CustomObj__r.A_CustomObj__r.id);
     }    

}
claperclaper
Super Strange. Are you positive all your relationship are filled in ?
KCBKCB
am 100% becz its working fine with the first code and also manually am checking. Even for me its doesn't make sence why its giving null trying to understand how the JVM pointer is behaving.
MSRMSR
Hi Chaitanya,

U can try this snippet in the 'before' event of the trigger to get whatever field from the grand parent to child.


// Get a list of all Parent Ids
Set<Id> parentIds = new Set<Id>();
for (child__c chld : trigger.new) { parentIds.add(chld.MyParent__c);
}
// Get a map of all Parents with field information
Map<Id, Parent__c> parentsById = new Map<Id, Parent__c>();
ParentsById.putAll([SELECT Id, MyParentfield1__c,MyParentfield2__c FROM Parent__c WHERE Id IN :parentIds]);
    for(child__c chld:trigger.new){
      chld.chldfield1__c=parentsById.get(chld.MyParent__c).MyParentfield1__c;                          chld.chldfield2__c=parentsById.get(chld.MyParent__c).MyParentfield2__c;
      }

If this works , mark it as answer so that others might benefit.
This was selected as the best answer
KCBKCB
Thanks Santosh, Claper and Kalpesh. Finally i understood we cannot retrive grand parent ID using Trigger.new (C__c.B_r.A__r.id) this can be done only in formula logic.