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.

  • 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 '16 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 '16 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 '16 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 '16 at 17:47
  • Oh got it, in such case this is a nice question. – Joca Sep 12 '16 at 17:50
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*/];
  • 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 '16 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 '16 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
}
  • 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 '16 at 18:29

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.