You need to sign in to do that
Don't have an account?
Any suggestions for when governor limits make your triggers useless??
Hi,
I'm getting frustrated with governor limits on triggers. I've taken all the correct steps as per the documentation (except the "helper class" one) and it's not a case anymore of coding correctly. It's now just a case of having a lot of data in the system.
In the "Force.com Cookbook" the chapter called "Avoiding Apex Governor Limits" has a beautiful example that I would like to use almost exactly as it is. In the example, whenever an address changes on an account, a trigger updates the address onto all the contacts.
Now this is wonderful if you don't have too many contacts, if you only sell to small companies. If you sell to large companies as we do and we have hundreds of sales and service contacts in a company, such a trigger will most likely hit governor limits no matter what you do.
What good would such a trigger be if it could only update, say, the first 100 contacts out of 500 and leave the other 400 unmodified?
What other magic tricks have you guys done when you've found yourself in similar situations? Do you just say, oh well, triggers can't help us or are there some really clever ways I've not thought of?
I hope I can get a couple of clever tips from the experts.
All Answers
Here's another nice simple example, besides the one in the Force.com Cookbook that I referred to previously.
You'll notice I've stuck in the "limit 99" just to make it work. Now if in case a Contact has more than 100 Subscriptions, the trigger won't error, but it will leave any Subscriptions after the first 99 untouched -- until such time as the trigger fires again for that Contact, at which time it will grab the next 99.
trigger updateSubs on Contact (after insert, after update) { map <Double,Id> contactMap = new map <Double,Id>(); for (Integer i = 0; i < Trigger.new.size(); i++) { if (Trigger.old[i].Star_Contact_Id__c != Trigger.new[i].Star_Contact_Id__c && Trigger.new[i].Star_Contact_Id__c !=null) { contactMap.put(Trigger.new[i].Star_Contact_Id__c,Trigger.new[i].Id); } } list <Subscription__c> updateSubsList = new list <Subscription__c>(); for (Subscription__c sub: [select Id, Contact__c, Star_Contact_Id__c from Subscription__c where Contact__c = null and Star_Contact_Id__c in :contactMap.keySet() limit 99 ]) { sub.Contact__c = contactMap.get(sub.Star_Contact_Id__c); updateSubsList.add(sub); } update updateSubsList; }
"massUpdateSubs.updateSubs(updateSubsList);" then I wrote this very simple class:
public class massUpdateSubs { // @future public static void updateSubs (List<Subscription__c> subscriptions) { update subscriptions; } }
It works with @future commented out -- doing the exact same thing as the trigger with the same governor limit as you'd expect for now.
When I uncomment the @future and save the class I get this error:
Save error: Unsupported parameter type LIST:SOBJECT:Subscription__c
Hello RDN_LHR,
I am having exact same problem. were you able to find the solutions to this limit?
Thanks
You can't pass Sobjects to an @future method because the Sobjects you're referring to may have changed by the time the @future runs, but you can pass a List<Id>. So instead of passing the List<Subscription__c>, pass a List<Id> and then, as your first line in the @future, do something like
List<Subscription__c> subs = [SELECT <fields you need> FROM Subscription__c WHERE Id IN :idList];
Yes I've solved it as recommended. My trigger passes a set of Id's to this helper class with @future and most of the work that used to be in the trigger is now in this class.
The trigger could only do 100 rows before throwing an error. Now in this method, I've tested with 500 rows and it worked. :smileyhappy:
public class massUpdateSubs { @future public static void updateSubs (Set<Id> contacts) { map <Double,Id> contactMap = new map<Double,Id>(); for (Contact c: [select Star_Contact_Id__c,Id from Contact where Id in :contacts]) { contactMap.put(c.Star_Contact_Id__c,c.Id); } list <Subscription__c> updateSubsList = new list <Subscription__c>(); for (Subscription__c sub: [select Id, Contact__c, Star_Contact_Id__c from Subscription__c where Contact__c = null and Star_Contact_Id__c n :contactMap.keySet()]) { sub.Contact__c = contactMap.get(sub.Star_Contact_Id__c); updateSubsList.add(sub); } update updateSubsList; } }
How can I optimize this following code. Line in red is giving me error
you didn't specify what error you were getting, but I would assume the problem is that you don't have Htlaccts defined anywhere.
At a minimum, it should be something like this:
List<Account> Htlaccts = new List<Account>(Database.query(qrystr));
I am getting Too many SOQL queries: 101 error
I defined my list as List<Account> Htlaccts = new List<Account> (); at the beginning of the method line 3 just forgot to in my posting.
If I change as per your suggestion, the query is still in for loop
Is that going to work I will try?
no, that will not work. You need to refactor your code to get that query outside of the loop.
The best model to use would be to capture all of the potential results in a map and then reference the map in your loop. Search for references to Bulk trigger, there is lots of sample code out there.
I did something like this and still got the error because it is in for loop
Well, like Jim said:
You need to refactor your code to get that query outside of the loop.
Umapen,
Look at my final example further up in this posting. I think it does what the guys are suggesting for you to do.
It took me a lot of frustrating practice and a lot of reading posts and making a lot of mistakes before I finally got the concept in my head. Even now, I think that maybe I've got it right. I'm still never 100% sure.