6

I want to avoid hitting the org's governor limits but at the same time I need to know if I was about to hit them. Here's what I have so far:

[
    SELECT convertCurrency(Price__c)
    FROM Object__c
    LIMIT :(Limits.getLimitQueryRows() - Limits.getQueryRows())
];

So this will save me from hitting the limits but it will not tell me that I was going to hit them.

Basically the case I am talking about is when the query LIMIT is 50k and the records are 50k. If Limits.getQueryRows() is 50k it doesn't necessarily mean that a limit would have been hit. But if the records are 50001 I want to know this so I can display an error on the page for the user.

I was thinking about using Count() somehow but not sure how I can achieve what I want. I am also trying to incorporate the solution without making an additional query.

5
  • What about making just an if-then-else condition before to run your query? if (threshold < 0){ // show error } else { // run query }, is that what you want to achieve?
    – Joca
    Sep 12, 2016 at 17:39
  • @Joca - I think what the OP is trying to say is if there have been 49990 rows returned and the next query will return 11 rows it will hit the limit.
    – Eric
    Sep 12, 2016 at 17:44
  • @Eric - that's correct. How do I catch the error though. I cannot catch limit exceptions. Also in my case it will return 10 rows and that will not throw an exception either. It will just stop querying after the 10th row. I want to know if there are more than 10 remaining rows so I can inform the user.
    – Arthlete
    Sep 12, 2016 at 17:46
  • @Arthlete - You are correct, sorry, keep forgetting that they cannot be caught.....(Which is silly btw) - I would impose my own limit then of say 40K or something and do custom error message. In a VF page you should not be returning 50K rows so the problem may be your design and not the limits.
    – Eric
    Sep 12, 2016 at 17:47
  • Oh got it, in such case this is a nice question.
    – Joca
    Sep 12, 2016 at 17:50

2 Answers 2

5

The way I see it, you have two options here:

  1. Display your message whenever you end up with 0 remaining query rows available.
  2. Write a batch that will store the number of records that object contains in a Hierarchy Custom Setting.

Either way, it will probably simplify repeated references to add a helper method:

public static Integer getRemainingQueryRows()
{
    return Limits.getLimitQueryRows() - Limits.getQueryRows();
}

For Option 1 your solution would simply look like:

someList = [
    SELECT convertCurrency(Price__c) FROM MyObject__c LIMIT :getRemainingQueryRows()
];
isQueryLimitConsumed = (0 == getRemainingQueryRows());

For Option 2 your current implementation would change to look more like:

isQueryComplete = MySetting__c.MyObjectCount__c > getRemainingQueryRows();
someList = [/*query*/];
2
  • Thank you. In regards to option 1 - displaying a message will be incorrect if the limits were 50k and the records in the db were 50k as well. Informing the user that not all records were displayed will be wrong. Any way to handle it without making a batch?
    – Arthlete
    Sep 12, 2016 at 17:55
  • I mean, if that's the route you choose you need to bake a little uncertainty into your message. Something like this result set may be incomplete. It's a corner case with a 50k limit though.
    – Adrian Larson
    Sep 12, 2016 at 17:59
2

Because of limitation that apex's Limits class can't provide that information, you may need to add your custom logic to know how many records remain after SOQL rows limit is hit. @Adrian idea about custom setting sounds great, I'd implement it using triggers:

trigger ObjectCount on Object__c(after insert, after delete) {
    if (Trigger.isInsert) {
        setting.MyObjectCount__c += Trigger.New.size();
    } else {
        setting.MyObjectCount__c -= Trigger.Old.size();
    }
    update setting;
}

Query:

List<Object__c> objs = [SELECT convertCurrency(Price__c) 
                        FROM Object__c 
                        LIMIT :(Limits.getLimitQueryRows() - Limits.getQueryRows())];
Integer remaining = setting.MyObjectCount__c - objs.size();
if (remaining > 0) {
    // show error
}
1
  • 2
    I think a batch would be easier to implement as it avoids any issues around row locking on the custom setting. You'd need to write one anyway to backfill the data. There are definitely a lot of approaches to how to populate that data though, and this one would certainly work.
    – Adrian Larson
    Sep 12, 2016 at 18:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .