function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
highland23highland23 

How to abstract a trigger into a trigger and class

I have a trigger that is doing a query and building a rather large found set.  It's one trigger that is firing as part of a larger execution, and it just so happens that the full execution is failing because I'm hitting a governor limit on the number of SOQL rows in the found sets.  Since the data isn't necessary to have immediately, I'm trying to get the queries in this trigger into a class with an @future notation.

 

The problem is that I'm not sure how to convert this trigger below into a trigger that references an Apex, so I can put the query into the @future notation.  Here's the trigger code I have now...

 

trigger MyRollup on CampaignMember (after delete, after insert, after undelete, after update) {

	Map<Id,Campaign> updateCampaigns = new Map<Id,Campaign>();
	Set<Id> updateCampaignIds = new Set<Id>();

	// If we are inserting, updating, or undeleting, use the new ID values
	if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete)
		for(CampaignMember testing:Trigger.new)
			updateCampaignIds.add(testing.CampaignId);

	// If we are updating, some campaigns might change, so include that as well as deletes
	if(Trigger.isUpdate || Trigger.isDelete)
		for(CampaignMember testing:Trigger.old)
			updateCampaignIds.add(testing.CampaignId);

	// Do not create a record for null field
	updateCampaignIds.remove(null);

	// Create in-memory copies for all campaigns that will be affected
	for(Id campaignId:updateCampaignIds)
		updateCampaigns.put(campaignId,new Campaign(id=campaignId,MyRollup__c=0));

	// Run an optimized query that looks for all campaigns that meet the if/then criteria
	for(CampaignMember testing:[select id,campaignid from CampaignMember where CampaignId in :updateCampaignIds and Ready__c=true])
		updateCampaigns.get(testing.CampaignId).MyRollup__c++;

	// Update all the campaigns with new values.
	Database.update(updateCampaigns.values());
		    
}

Any recommendations as to how I can modify this trigger so that it's paired with a new Apex class?

Cheers!

Best Answer chosen by Admin (Salesforce Developers) 
Scott_VSScott_VS

Make your @future method take in a set of Id's, then just pass your updateCampaignIds set.

 

trigger MyRollup on CampaignMember (after delete, after insert, after undelete, after update) {

	Map<Id,Campaign> updateCampaigns = new Map<Id,Campaign>();
	Set<Id> updateCampaignIds = new Set<Id>();

	// If we are inserting, updating, or undeleting, use the new ID values
	if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete)
		for(CampaignMember testing:Trigger.new)
			updateCampaignIds.add(testing.CampaignId);

	// If we are updating, some campaigns might change, so include that as well as deletes
	if(Trigger.isUpdate || Trigger.isDelete)
		for(CampaignMember testing:Trigger.old)
			updateCampaignIds.add(testing.CampaignId);

	// Do not create a record for null field
	updateCampaignIds.remove(null);

        // Call future method
        MyApexClass.handleRollup(updateCampaignIds);
}

 

All Answers

Scott_VSScott_VS

Make your @future method take in a set of Id's, then just pass your updateCampaignIds set.

 

trigger MyRollup on CampaignMember (after delete, after insert, after undelete, after update) {

	Map<Id,Campaign> updateCampaigns = new Map<Id,Campaign>();
	Set<Id> updateCampaignIds = new Set<Id>();

	// If we are inserting, updating, or undeleting, use the new ID values
	if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete)
		for(CampaignMember testing:Trigger.new)
			updateCampaignIds.add(testing.CampaignId);

	// If we are updating, some campaigns might change, so include that as well as deletes
	if(Trigger.isUpdate || Trigger.isDelete)
		for(CampaignMember testing:Trigger.old)
			updateCampaignIds.add(testing.CampaignId);

	// Do not create a record for null field
	updateCampaignIds.remove(null);

        // Call future method
        MyApexClass.handleRollup(updateCampaignIds);
}

 

This was selected as the best answer
highland23highland23

Thanks, I think that makes sense.  I went ahead and built the following method, based on your advice...

 

public with sharing class MyApexClass {

	@Future
    public static void handleRollup(Set<Id> updateCampaignIds) { 
		
		Map<Id,Campaign> updateCampaigns = new Map<Id,Campaign>();
	

	// Create in-memory copies for all campaigns that will be affected
	for(Id campaignId:updateCampaignIds)
		updateCampaigns.put(campaignId,new Campaign(id=campaignId,MyRollup__c=0));

	// Run an optimized query that looks for all campaigns that meet the if/then criteria
	for(CampaignMember testing:[select id,campaignid from CampaignMember where CampaignId in :updateCampaignIds and Ready__c=true])
		updateCampaigns.get(testing.CampaignId).MyRollup__c++;

	// Update all the campaigns with new values.
	Database.update(updateCampaigns.values());

}
}

 ....but I'm receiving the following error from the IDE on the trigger...

 

"Method does not exist or incorrect signature: MyApexClass.handleRollup(SET<Id>)"

 

I figure I'm doing something quite obviously wrong in creating the method, but I'm not sure what.  Might you have some guidance?

Thanks!

Scott_VSScott_VS

That class works fine in my setup.

 

Is your IDE in sync with your sever?

highland23highland23

That's it, got it to work!  Many thanks for the assistance!