+ Start a Discussion
KlivingstonKlivingston 

Apex Trigger to change Record Type on child object

I need some help with Apex code and hope you will be able to provide me with some solutions. Here is the scenario:

 

Account Object:

We have workflow rules that check the Regional manager within the Account objects and if it is equal to certain people it will change the Record type of the Account object, which then will change the page layout of the account object. (This works fine)

 

Sales History (Custom Child Object)

Then we have workflow rules for Child Object (Sales History) that check if the Account Record Types is equal to certain value (i.e. Regional_Record_Type), if yes then it should change/update the record type within the Sales History object which should change the page layout of the Sales History.(Not working)

 

 

 

I have tried the normal workflow rules and it doesn’t seems to be working.

 

Thanks in advance.

Peter_sfdcPeter_sfdc

I would guess that the problem is that you cannot trigger a workflow on a child record when the parent is created. Is this what you mean? 

 

What is your experience with coding in general? And what is your experience with coding in Apex? 

KlivingstonKlivingston

Yes I cannot trigger the workflow when a parent is created or edited. I have some experience in coding but I am totally new to Apex.

Yoganand GadekarYoganand Gadekar

You can do that in a trigger, you can get all the child records of each account using "Relationship Query" and the uodate all the child records for each of the account...

Go throgh this to know more about child relationship query, see if it helps you,

cloudforce4u.blogspot.com/.../sometimes-we-need-list-of-all-child.html

KlivingstonKlivingston

Thank you, the link you provided is not available but I searched the Relationship query and I am not sure if I can change child record type based on a parents record type.

Peter_sfdcPeter_sfdc
You definitely can. Here's the thing, though, the record type ID is not going to be the same. So:

1. Create record types for each object with the same name.
2. Create some kind of map that links parent to child record type. To make sure it scales easily and can be modified as new record types appear or are removed, make this in a custom setting.
3. In your trigger, you simply use your custom setting to do a quick lookup of the corresponding record Ids and build a map in Apex so that whatever record type ID is set in Parent, you set the correct record type in the child.
KlivingstonKlivingston

Here is what I have so far:

trigger SalesHistoryRecordTypeTrigger on Account (after insert, after update){
      //Query for the Account record types
    List<RecordType> rtypes = [Select Name, Id From RecordType 
    where sObjectType='Account' and isActive=true];
    
    //Create a map between the Record Type Name and Id for easy retrieval
    Map<String,String> accountRecordTypes = new Map<String,String>{};
    for(RecordType rt: rtypes)
    accountRecordTypes.put(rt.Name,rt.Id);
    
    for(Account a: Trigger.new){
    
        //Use the Map collection to dynamically retrieve the Record Type Id
        //Avoid hardcoding Ids in the Apex code
        if(a.RecordTypeId==accountRecordTypes.get('Regional_View_Lit_ppl')){ 
            Sales_History_YTD__c.RecordType = 'Regional_View_Record';
        }else if(a.RecordTypeId==accountRecordTypes.get('Dollar View')){
            Sales_History_YTD__c.RecordType = 'National_Dollar_View_Record';
        }else if(a.RecordTypeId==accountRecordTypes.get('Dual Currency View')){ 
              Sales_History_YTD__c.RecordType = 'National_Dule_Record';  
        }
        
    } 

 but I face some errors like:

Error: Compile Error: Illegal assignment from String to SOBJECT:Sales_History_YTD__c at line 16 column 13

 

perhaps I am missing some part as well, Thanks for you help.

asish1989asish1989

Sales_History_YTD__c.RecordType ?

You need to write like this 

Sales_History_YTD__c.RecordTypeId = some recordType id;

 

RecordType rt = [SELECT id,Name 
                             FROM RecordType 
                             WHERE SobjectType='Sales_History_YTD__c' AND Name='Regional_View_Record'];

 

if Only one recordtype exists on Sales_History_YTD__c whose name is Regional_View_Record then it is fine otherwise you can take a recordtype list.

Sales_History_YTD__c.RecordTypeId = rt.id;

KlivingstonKlivingston

Hi I have changed that to:

 

trigger SalesHistoryRecordTypeTrigger on Account (after insert, after update){
      //Query for the Account record types
    List<RecordType> rtypes = [Select Name, Id From RecordType 
    where sObjectType='Account' and isActive=true];
    
    //Create a map between the Record Type Name and Id for easy retrieval
    Map<String,String> accountRecordTypes = new Map<String,String>{};
    for(RecordType rt: rtypes)
    accountRecordTypes.put(rt.Name,rt.Id);
    
    for(Account a: Trigger.new){
    
        //Use the Map collection to dynamically retrieve the Record Type Id
        //Avoid hardcoding Ids in the Apex code
        if(a.RecordTypeId==accountRecordTypes.get('Regional_View_Lit_ppl')){ 
           RecordType rt = [SELECT id,Name 
                             FROM RecordType 
                             WHERE SobjectType='Sales_History_YTD__c' AND Name='Regional_View_Record'];
           Sales_History_YTD__c.RecordTypeId = rt.id;
           
        }else if(a.RecordTypeId==accountRecordTypes.get('Dollar View')){
             RecordType rt = [SELECT id,Name 
                             FROM RecordType 
                             WHERE SobjectType='Sales_History_YTD__c' AND Name='National_Dollar_View_Record'];
            Sales_History_YTD__c.RecordTypeId = rt.id;        
           
        }else if(a.RecordTypeId==accountRecordTypes.get('Dual Currency View')){ 
           RecordType rt = [SELECT id,Name 
                             FROM RecordType 
                             WHERE SobjectType='Sales_History_YTD__c' AND Name='National_Dule_Record'];
           Sales_History_YTD__c.RecordTypeId = rt.id;
        }
        
    }

}

 Now I get this error:

Error: Compile Error: Expression cannot be assigned at line -1 column -1

 

 

Peter_sfdcPeter_sfdc

Cardinal rule: don't make trips to the DB in the middle of a for loop. 

 

And don't make a second trip, if you can get what you need with one. I would structure my code like this (although I've not done this in an org or IDE, so there may be syntax errors). 

 

trigger SalesHistoryRecordTypeTrigger on Account (after insert, after update){
    //One query, fill two maps. 
    Map<String,Id> accountRecordTypes = new Map<String,Id>(); //<=this was {} before
    Map<String,Id> ytdRTMap = new Map<String,Id>();
    for(RecordType rt: [Select Name, Id, sObjectType 
From RecordType
Where sObjectType in ('Account','Sales_History_YTD__c')
and isActive=true]) { if (sObjectType.equals('Account')) { accountRecordTypes.put(rt.Name,rt.Id); } else { //<=could be else if for more certainty... ytdRTMap.put(rt.name,rt.Id); }
} for(Account a : trigger.new){ //NO QUERIES INSIDE OF FOR LOOPS!!! BAD! BAD! BAD! if(a.RecordTypeId==accountRecordTypes.get('Regional_View_Lit_ppl')){ Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Regional_View_Lit_ppl'); }else if(a.RecordTypeId==accountRecordTypes.get('Dollar View')){ Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Dollar View');; }else if(a.RecordTypeId==accountRecordTypes.get('Dual Currency View')){ Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Dual Currency View');; } } }

 Not sure what was the cause of your error. It is a strange one. It might have been you attempting to invoke the map constructor with the {} characters after. I don't think that is allowed. 

 

This code also avoids any queries in your for loop, and going back to query the same object a second time when you've already been there. 

 

I can think of other ways to construct this and improvements on my code (like no hard coding of strings...I really don't like that in production code), but this should give you a good template to work with that will reduce risk of governor limit exceptions. 

KlivingstonKlivingston

Thanks Peter

 

for some reason it doesnot like sObjectType

Error: Compile Error: Variable does not exist: sObjectType at line 8 column 13

 

Peter_sfdcPeter_sfdc
Strange. That query works exactly as is when I run it in the developer console query tool.
KlivingstonKlivingston

Cannot figure out how to fix this, still shows this error:

Error: Compile Error: Variable does not exist: sObjectType at line 8 column 13

 

Thanks for your help

Peter_sfdcPeter_sfdc
Can you repost your code exactly as it is now in your trigger?
KlivingstonKlivingston
trigger SalesHistoryRecordTypeTrigger on Account (after insert, after update){
    //One query, fill two maps. 
    Map<String,Id> accountRecordTypes = new Map<String,Id>(); //<=this was {} before
    Map<String,Id> ytdRTMap = new Map<String,Id>();
    for(RecordType rt: [Select Name, Id, sObjectType                         
    From RecordType                         
    Where sObjectType in ('Account','Sales_History_YTD__c')                               and isActive=true]) {
        if (sObjectType.equals('Account')) {
            accountRecordTypes.put(rt.Name,rt.Id);
        } else { //<=could be else if for more certainty...
            ytdRTMap.put(rt.name,rt.Id);
        }    }
    for(Account a : trigger.new){
    
        //NO QUERIES INSIDE OF FOR LOOPS!!! BAD! BAD! BAD!

        if
(a.RecordTypeId==accountRecordTypes.get('Regional_View_Lit_ppl')){ 
           Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Regional_View_Lit_ppl');     
        }else if(a.RecordTypeId==accountRecordTypes.get('Dollar View')){
            Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Dollar View');        
        }else if(a.RecordTypeId==accountRecordTypes.get('Dual Currency View')){ 
           Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Dual Currency View');       
         }
        
    }

}

 

Peter_sfdcPeter_sfdc

That's what happens when you post code that you've written by free hand. I was looking at the SOQL query, but it is the if statement that is the problem. 

 

for(RecordType rt: [Select Name, Id, sObjectType                         
                      From RecordType                         
                      Where sObjectType in ('Account','Sales_History_YTD__c')
                      and isActive=true]) {
        if (rt.sObjectType.equals('Account')) { <--forgot rt.

 

KlivingstonKlivingston

I have tried that before it solved the problem and I was not sure if it was right but it shows this error now:

Error: Method does not exist or incorrect signature: [String].equal(String) at line 9 column 13

Peter_sfdcPeter_sfdc

You need to cast the picklist to String, it would appear.

 

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_string.htm

 

That would end up looking like this. 

if (String.valueof(rt.sObjectType).equalsIgnoreCase('Account'))

I also changed the method to the case-insensitive version. Probably safer. 

 

 That should do it. 

 

 

KlivingstonKlivingston

Wonderful :) that did work HOWEVER now I get this error: Error: Compile Error: Expression cannot be assigned at line -1 column -1.  Once more thanks for the help.

trigger SalesHistoryRecordTypeTrigger on Account (after insert, after update){
    //One query, fill two maps. 
    Map<String,Id> accountRecordTypes = new Map<String,Id>();  
    Map<String,Id> ytdRTMap = new Map<String,Id>();
    for(RecordType rt: [Select Name, Id, sObjectType                         
    From RecordType                         
    Where sObjectType in ('Account','Sales_History_YTD__c')and isActive=true]) 
    {
        if(String.valueof(rt.sObjectType).equalsIgnoreCase('Account'))
            accountRecordTypes.put(rt.Name,rt.Id);
        else  
            ytdRTMap.put(rt.name,rt.Id);       
    }
    for(Account a : trigger.new){
        if(a.RecordTypeId==accountRecordTypes.get('Regional_View_Lit_ppl')){ 
           Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Regional_View_Lit_ppl');     
        }else if(a.RecordTypeId==accountRecordTypes.get('Dollar View')){
            Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Dollar View');        
        }else if(a.RecordTypeId==accountRecordTypes.get('Dual Currency View')){ 
           Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Dual Currency View');       
         }  
    }
}

 

KlivingstonKlivingston

I think the problem is with the second for loop but I cannot find it !!

Sales_History_YTD__c.RecordTypeId = ytdRTMap.get('Regional_View_Lit_ppl');

Peter_sfdcPeter_sfdc
Sorry...nothing is jumping out at me either.