I had used a mapping to get out of an issue of querying within trigger.new, and when I tested a few times doing a "Mass Order" functionality (where orders are made for a mass number of accounts), it went through, no errors. I went to test it again, and I got an error of 101 queries.

This trigger fires before and after insert, and before update. In none of these conditions (ie. in no trigger.isUpdate condition etc.) is the query that's putting it over the limit. It's a query for the Pricebook...

pbList = [Select ID 
          From Pricebook2 
          Where IsActive = true AND IsStandard = true];

... and I'm guessing that even though it's not in trigger.new, it's just going over because this is inserting SO many orders. This seems like a very necessary thing and I'm wondering, what is my alternative to this query other than hard-coding in the ID? As mentioned, the only errors I'd gotten before was querying account info in Trigger.new, and when I changed it to a mapping implementation, this functionality did work fine. It does make sense that this would come up, though. What are my options?

  • 1
    This is basically recursion in Trigger. Set up the system.debug you would get that debug printed 100 times. – Ashwani Jan 24 '17 at 16:55
  • I believe you -- I understand the problem, but I can't think of a way to avoid this...are there common work-arounds for triggers that are going to fire over 100 times..? Also, it isn't recursion -- the order trigger isn't making more orders. – Natalie Spatharakis Jan 24 '17 at 16:55
  • How many orders are you trying to insert at one time? How do you know that this one particular query is being fired so many times? Usually in these situations, the culprit is that you have triggers (and possibly workflow rules, or process builder processes) that are interacting with one another (i.e. an update to an OpportunityLineItem causes an update to the Opportunity, which causes an update to the Account, etc...) – Derek F Jan 24 '17 at 16:56
  • I suppose that's true, I don't know for a fact where the bulk is happening, but I know that what I'm doing inserts a huge amount of orders, and if I have 1 standalone query on a trigger that fires on insert, I know that that's going to be the majority of the issue that I'd need to address (since it very well could be inserting, say, 2,000 orders) – Natalie Spatharakis Jan 24 '17 at 16:57
  • If your trigger is properly bulkified (and it sounds like it is), then 2000 orders should be no problem. If you issue a DML insert for 2000 orders (and you're not using a Data Loader/ the bulk API), your trigger will run 10 times (with 200 records, the max, per invocation of your trigger). Situations like these are where you start needing to use the dev console to get a better idea of what is happening, and when. Specifically, the 'analysis' perspective. – Derek F Jan 24 '17 at 17:06

This may not be your issue but certainly since there is only one standard pricebook, you should change you access to it as follows (lazy loading)

static ID stdPbId { get { return stdPbId == null 
                            ? stdPbId = [Select ID 
                                          From Pricebook2 
                                          Where IsActive = true AND IsStandard = true][0].Id
                            : stdPbId;} set;}

This query will run only once in the whole transaction.

Or, to make it more useful across other use cases, two Util methods:

private static Pricebook2  stdPriceBook; // Singleton, remember when first referenced

//  ------------------------------------------------------
//  getStdPricebookId : as of V31, testmethods can locate std pricebook wo seeAlldata=true
//  ------------------------------------------------------
public static ID getStdPricebookId() {
    if (Test.isRunningTest())   return Test.getStandardPricebookId();
    return getStdPricebook().id;    

//  -------------------------------------------------------
//  getStdPriceBook: Singleton
//  -------------------------------------------------------
public static Pricebook2    getStdPriceBook () {
    if (stdPriceBook == null) 
        stdPriceBook    = [select id, name from Pricebook2 where isStandard = true limit 1];
    return stdPriceBook;    
| improve this answer | |
  • Worth mentioning the name of this well known pattern. – Adrian Larson Jan 24 '17 at 17:19
  • @AdrianLarson - you mean Singleton pattern? – cropredy Jan 24 '17 at 17:22
  • Well I was referring to lazy loading, of which singleton is a flavor I suppose. – Adrian Larson Jan 24 '17 at 17:23
  • Also I think you'll get better coverage on the pricebook id if you use ternary logic. – Adrian Larson Jan 24 '17 at 17:24
  • @AdrianLarson; as you can imagine, I just copy-pasted from my library but, yes. – cropredy Jan 24 '17 at 17:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.