+ Start a Discussion
KevinA.ax1880KevinA.ax1880 

Trigger to affect relate objects when a record is updated to active = 0

Hi, We are just getting started with SalesForce, and I am a developer proficient in .Net & SQL, I am having a hard time finding examples for updating child records of a custom object when it has it's status updated. I believe a trigger are what I am looking for, but the examples I am finding are all very generic. I would like some help in how to reference current the record's ID and how to perform an update of related child records. The two paradiagms I am familiar with are vb.net recordsets & SQL updates. I am literally starting with nothing: trigger trDeleteRelatedRecipients on Report_Package__c (after update) { } Any help would be greatly appreciated!
Best Answer chosen by Admin (Salesforce Developers) 
firechimpfirechimp

Hi Kevin,

Sorry I haven't been around to help more, it has been a busy week.

 

The modifications to the code that you have made look pretty good to me!

 

But I would make the following changes, so you are only doing one DML statment, rather than it been in a loop.

Also you don't need the try catch unless you wish to throw your own custom exception messages, you can do this as shown in the example in the updated code below:

public class  ReportPackageHelper {
    /**
    * @description Delete the related recipients
    **/
    public static void deleteRecipients(Map<Id,Report_Package__c> oldMap, Map<Id,Report_Package__c> newMap){
        List<Id> reportPackagesMatchingCriteria = new List<Id>();

        //1. find all records we want to modify (this should be bulkified)
        for(Id rpId : oldMap.keySet()){
            //check if status has changed to active
            if(oldMap.get(rpId).Active__c == true && newMap.get(rpId).Active__c == false){
                reportPackagesMatchingCriteria.add(rpId);
            }
        }
      
        
        //2. Query for child records for all those that matched criteria
        List <Package_Recipient__c> prList = [select Id, Report_Package__c, Deletion_Date__c from Package_Recipient__c where Report_Package__c in :reportPackagesMatchingCriteria];

        //3. Update recipientsForDeletion
        for(Package_Recipient__c pr: prList){
            pr.Deletion_Date__c = Date.Today();
        }

        try{  
            update prList;
        }catch (DmlException ex){
            throw new customException('Recipients For Deletion Could Not Be Updated', ex);
        }catch (Exception e){
            System.debug('ERROR ' + e);
        }

    }

    //Custom Exception Class
    public class customException extends Exception {}
}

 

Hope this helps!

 

 

All Answers

firechimpfirechimp

Hi Kevin,

 

For Trigger Code:

trigger ReportPackageTrigger on Report_Package__c (after update) {
       //call delete recipients method, it is good practice to have
       //only one trigger per object, and keep all the logic in separate
       //appropriate classes (to make more maintainable, easier to test etc...)
       ReportPackageHelper.deleteRecipients(trigger.oldMap,trigger.newMap);

} 

 

Class for method:

public class with sharing ReportPackageHelper {
	/**
	* @description Delete the related recipients
	**/
	public static void deleteRecipients(Map<Id,Report_Package__c> oldMap, Map<Id,Report_Package__c> newMap){
		List<Id> reportPackagesMatchingCriteria = new List<Id>();

		//1. find all records we want to modify (this should be bulkified)
		for(Id rpId : oldMap.keySet()){
			//check if status has changed to active
			if(oldMap.get(rpId).Status__c != 'Active' && newMap.get(rpId).Status__c == 'Active'){
				reportPackagesMatchingCriteria.add(rpId);
			}
		}

		//2. Query for child records for all those that matched criteria
		List<Recipient__c> recipientsForDeletion = [select Id, Report_Package__c from Recipient__c where Report_Package__c in :reportPackagesMatchingCriteria];

		//3. delete all records
		delete recipientsForDeletion;
	}

}

 

You could actually tidy up the above a little more, but I thought I would seperate it out a bit so you can get a feel for how it works!

 

KevinA.ax1880KevinA.ax1880

Hi Gary,

 

 

 

Thanks for your reply. This does look helpful. If you don't mind, I have a few follow up questions:

 

1. I don't appear to be able to save the Class code in the same window as the trigger code. Where am I able to save the Class?

 

2. It appears that oldMap is a variable set holding the current records ID. Does that sound correct?

 

3. What does the newMap parameter signify?

 

EDIT: I found the Apex Classes, although it is balking at the 'with sharing' clause.  In your class where you are checking the status to inactive to active the field is Active__c  datatype: Formula (Checkbox), and will not compile when I try & evaluate with modified logic.  Would you have anything to offer that may help getting past this obstacle?:

            if(oldMap.get(rpId).Active__c != 1 && newMap.get(rpId).Active__c == 1){
                reportPackagesMatchingCriteria.add(rpId);
            }

 

 

And finally, thanks again for the reply. I did search for quite a bit before posting this forum question. Would you know of any resources that would help me transition my VB and/or SQL knowledge to assist in my learning the apex methods and techniques?

KevinA.ax1880KevinA.ax1880

I am able to get the Class to save/compile with the modifications below.   Now onto seeing if the modified Class can be called from the trigger.  Please stand by. UPDATE: Looks like it worked!  Speaking with my manager, it may be more appropriate to flag/update the records instead of physically deleting them.  Do you have an example of an update sub?  My attempt to modify the script with changes found on the force.com help are throwing an error:

 

Error: Compile Error: Initial term of field expression must be a concrete SObject: LIST<Package_Recipient__c> at line 22 column 9

 

        //2. Query for child records for all those that matched criteria
        List<Package_Recipient__c> recipientsForDeletion = [select Id, Report_Package__c from Package_Recipient__c where Report_Package__c in :reportPackagesMatchingCriteria];

        //3. delete all records
       // delete recipientsForDeletion;
        //update records delete_date
        recipientsForDeletion.Deletion_Date__c = Date();
        try
        {
        update recipientsForDeletion;
        }
        catch (DMLException e)
        {
        
        }

 

 

I still would love to know if you have a good resource for these types of questions.

 

public class  ReportPackageHelper {
    /**
    * @description Delete the related recipients
    **/
    public static void deleteRecipients(Map<Id,Report_Package__c> oldMap, Map<Id,Report_Package__c> newMap){
        List<Id> reportPackagesMatchingCriteria = new List<Id>();

        //1. find all records we want to modify (this should be bulkified)
        for(Id rpId : oldMap.keySet()){
            //check if status has changed to active
            if(oldMap.get(rpId).Active__c == TRUE && newMap.get(rpId).Active__c == False){
                reportPackagesMatchingCriteria.add(rpId);
            }
        }

        //2. Query for child records for all those that matched criteria
        List<Package_Recipient__c> recipientsForDeletion = [select Id, Report_Package__c from Package_Recipient__c where Report_Package__c in :reportPackagesMatchingCriteria];

        //3. delete all records
        delete recipientsForDeletion;
    }

}

 

KevinA.ax1880KevinA.ax1880

Here is my final solution that I was able to get to work.  I would appreciate any comments if there may have been a better solution.  I basically had to modify firechimp's script from a delete to an update using a for loop.  I am using a system.debug when trapping the error, but would like some feedback on providing an interactive error response (message box)

 

public class  ReportPackageHelper {
    /**
    * @description Delete the related recipients
    **/
    public static void deleteRecipients(Map<Id,Report_Package__c> oldMap, Map<Id,Report_Package__c> newMap){
        List<Id> reportPackagesMatchingCriteria = new List<Id>();

        //1. find all records we want to modify (this should be bulkified)
        for(Id rpId : oldMap.keySet()){
            //check if status has changed to active
            if(oldMap.get(rpId).Active__c == TRUE && newMap.get(rpId).Active__c == FALSE){
                reportPackagesMatchingCriteria.add(rpId);
            }
        }
      
        Date today = Date.Today();
        //2. Query for child records for all those that matched criteria

        List <Package_Recipient__c> rcp = [select Id, Report_Package__c, Deletion_Date__c from Package_Recipient__c where Report_Package__c in :reportPackagesMatchingCriteria];

        
        

        //3. Update recipientsForDeletion;
        try
        {  
        for(Package_Recipient__c pr: rcp)
            {
            pr.Deletion_Date__c = today;
            }
            update rcp;
        }
        catch (Exception e) 
        {
        System.debug('ERROR ' + e);
        }

    }

}

 

 

 

 

firechimpfirechimp

Hi Kevin,

Sorry I haven't been around to help more, it has been a busy week.

 

The modifications to the code that you have made look pretty good to me!

 

But I would make the following changes, so you are only doing one DML statment, rather than it been in a loop.

Also you don't need the try catch unless you wish to throw your own custom exception messages, you can do this as shown in the example in the updated code below:

public class  ReportPackageHelper {
    /**
    * @description Delete the related recipients
    **/
    public static void deleteRecipients(Map<Id,Report_Package__c> oldMap, Map<Id,Report_Package__c> newMap){
        List<Id> reportPackagesMatchingCriteria = new List<Id>();

        //1. find all records we want to modify (this should be bulkified)
        for(Id rpId : oldMap.keySet()){
            //check if status has changed to active
            if(oldMap.get(rpId).Active__c == true && newMap.get(rpId).Active__c == false){
                reportPackagesMatchingCriteria.add(rpId);
            }
        }
      
        
        //2. Query for child records for all those that matched criteria
        List <Package_Recipient__c> prList = [select Id, Report_Package__c, Deletion_Date__c from Package_Recipient__c where Report_Package__c in :reportPackagesMatchingCriteria];

        //3. Update recipientsForDeletion
        for(Package_Recipient__c pr: prList){
            pr.Deletion_Date__c = Date.Today();
        }

        try{  
            update prList;
        }catch (DmlException ex){
            throw new customException('Recipients For Deletion Could Not Be Updated', ex);
        }catch (Exception e){
            System.debug('ERROR ' + e);
        }

    }

    //Custom Exception Class
    public class customException extends Exception {}
}

 

Hope this helps!

 

 

This was selected as the best answer
KevinA.ax1880KevinA.ax1880

HI Gary,

 

Thanks for the response & I can understand the delay.  No worries.  It helped push me to dig further myself.  I'll check out your example once i get some coffee... - Thanks, Kevin

KevinA.ax1880KevinA.ax1880

Hi Gary,

 

Moving on, can you reccommend a resource for going over the basics of apex programming?  I am kinda just hunting & pecking.

 

 - Thanks, Kevin

KevinA.ax1880KevinA.ax1880

Can anyone help me with a raise error method that will display only my custom text & not all of the associated error/SalesForce messaging?

 

Curently, the class customException method that Gary helped me with displays something like below, and I am wanting to only display the message that I have delineated with the underscores____Cannot un-end date a recipient.  Create a new contact____:

 

Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger PackageRecipientTrigger caused an unexpected exception, contact your administrator: PackageRecipientTrigger: execution of BeforeUpdate caused by: ReportPackageHelper.customException: ______Cannot un-end date a recipient. Create a new contact._____: Class.ReportPackageHelper: line 7, column 1