You need to sign in to do that
Don't have an account?
Ashley Cobb 24
System.LimitException: Too many SOQL queries: 101 Stack Trace: Class.RollUpSummaryUtility.rollUpTrigger: line 83, column 1
Hello!
I am trying to upload new code, and am coming up with the error "System.LimitException: Too many SOQL queries: 101
Stack Trace: Class.RollUpSummaryUtility.rollUpTrigger: line 83, column 1". I am a very new Developer, but do not understand why I am getting the error. It seems to be the bolded area. Any help would be appreciated!!
public class RollUpSummaryUtility {
public class fieldDefinition {
public String operation {get;set;}
public String childField {get;set;}
public String parentField {get;set;}
public fieldDefinition (String o, String c, String p) {
operation = o;
childField = c;
parentField = p;
}
}
public static void rollUpTrigger(list<fieldDefinition> fieldDefinitions, list<sObject> records, String childObject, String childParentLookupField, String parentObject, String queryFilter) {
//Limit the size of list by using Sets which do not contain duplicate elements prevents hitting governor limits.
set<Id> parentIds = new set<Id>();
for(sObject s : records) {
parentIds.add((Id)s.get(childParentLookupField));
}
//Populate query text strings to be used in child aggregrator and parent value assignment.
String fieldsToAggregate = '';
String parentFields = '';
for(fieldDefinition d : fieldDefinitions) {
fieldsToAggregate += d.operation + '(' + d.childField + ') ' + ', ';
parentFields += d.parentField + ', ';
}
//Using dynamic SOQL with aggergate results to populate parentValueMap.
String aggregateQuery = 'Select ' + fieldsToAggregate +
childParentLookupField + ' from ' + childObject + ' where ' +
childParentLookupField + ' IN :parentIds ' + queryFilter + ' ' +
' group by ' + childParentLookupField;
//Map will contain one parent record Id per one aggregate object.
map<Id, AggregateResult> parentValueMap = new map <Id, AggregateResult>();
for(AggregateResult q : Database.query(aggregateQuery)){
parentValueMap.put((Id)q.get(childParentLookupField), q);
}
//List of parent object records to update.
list<sObject> parentsToUpdate = new list<sObject>();
String parentQuery = 'select ' + parentFields + ' Id ' + ' from ' + parentObject + ' where Id IN :parentIds';
//For each affected parent object, retrieve aggregate results and for each field definition add aggregate value to parent field.
for(sObject s : Database.query(parentQuery)) {
Integer row = 0; //row counter reset for every parent record
for(fieldDefinition d : fieldDefinitions) {
String field = 'expr' + row.format();
AggregateResult r = parentValueMap.get(s.Id);
//r will be null if no records exist (e.g. last record deleted)
if(r != null) {
Decimal value = ((Decimal)r.get(field) == null ) ? 0 :
(Decimal)r.get(field);
s.put(d.parentField, value);
} else {
s.put(d.parentField, 0);
}
row += 1; //plus 1 for every field definition after first
}
parentsToUpdate.add(s);
}
//Ff parent records exist, perform update of all parent records with a single DML statement.
if(parentsToUpdate.Size() > 0) {
update parentsToUpdate;
}
}
}
I am trying to upload new code, and am coming up with the error "System.LimitException: Too many SOQL queries: 101
Stack Trace: Class.RollUpSummaryUtility.rollUpTrigger: line 83, column 1". I am a very new Developer, but do not understand why I am getting the error. It seems to be the bolded area. Any help would be appreciated!!
public class RollUpSummaryUtility {
public class fieldDefinition {
public String operation {get;set;}
public String childField {get;set;}
public String parentField {get;set;}
public fieldDefinition (String o, String c, String p) {
operation = o;
childField = c;
parentField = p;
}
}
public static void rollUpTrigger(list<fieldDefinition> fieldDefinitions, list<sObject> records, String childObject, String childParentLookupField, String parentObject, String queryFilter) {
//Limit the size of list by using Sets which do not contain duplicate elements prevents hitting governor limits.
set<Id> parentIds = new set<Id>();
for(sObject s : records) {
parentIds.add((Id)s.get(childParentLookupField));
}
//Populate query text strings to be used in child aggregrator and parent value assignment.
String fieldsToAggregate = '';
String parentFields = '';
for(fieldDefinition d : fieldDefinitions) {
fieldsToAggregate += d.operation + '(' + d.childField + ') ' + ', ';
parentFields += d.parentField + ', ';
}
//Using dynamic SOQL with aggergate results to populate parentValueMap.
String aggregateQuery = 'Select ' + fieldsToAggregate +
childParentLookupField + ' from ' + childObject + ' where ' +
childParentLookupField + ' IN :parentIds ' + queryFilter + ' ' +
' group by ' + childParentLookupField;
//Map will contain one parent record Id per one aggregate object.
map<Id, AggregateResult> parentValueMap = new map <Id, AggregateResult>();
for(AggregateResult q : Database.query(aggregateQuery)){
parentValueMap.put((Id)q.get(childParentLookupField), q);
}
//List of parent object records to update.
list<sObject> parentsToUpdate = new list<sObject>();
String parentQuery = 'select ' + parentFields + ' Id ' + ' from ' + parentObject + ' where Id IN :parentIds';
//For each affected parent object, retrieve aggregate results and for each field definition add aggregate value to parent field.
for(sObject s : Database.query(parentQuery)) {
Integer row = 0; //row counter reset for every parent record
for(fieldDefinition d : fieldDefinitions) {
String field = 'expr' + row.format();
AggregateResult r = parentValueMap.get(s.Id);
//r will be null if no records exist (e.g. last record deleted)
if(r != null) {
Decimal value = ((Decimal)r.get(field) == null ) ? 0 :
(Decimal)r.get(field);
s.put(d.parentField, value);
} else {
s.put(d.parentField, 0);
}
row += 1; //plus 1 for every field definition after first
}
parentsToUpdate.add(s);
}
//Ff parent records exist, perform update of all parent records with a single DML statement.
if(parentsToUpdate.Size() > 0) {
update parentsToUpdate;
}
}
}
If you figure out what exactly is calling this function or have any more information on this i would be more than glad to help resolve.
One solution i can think of is to cache the values returned in the parentquery so you dont query the same object. You can achieve this by declaring a static variable for the class. something like
and store new results. This map will fill up as you query for new records that are not in this map
Hope this helps!
AM
The error might be in the trigger or apex class that is calling this code.
This class looks fine. if you are calling this class with in a trigger make sure it is not getting called recursively.
This is the trigger that is using the code above.
trigger ContractRollUpAssets on Asset (after insert, after update, after delete, after undelete) {
//Rolls up Assets fields on the related Contract records.
//=============================================================
if(trigger.isInsert || trigger.isUpdate || trigger.isUnDelete){
//Create the list of rollups we want.
list<RollUpSummaryUtility.fieldDefinition> fieldDefinitions = new list<RollUpSummaryUtility.fieldDefinition>{
new RollUpSummaryUtility.fieldDefinition('COUNT', 'ID', 'Active_Assets__c')
};
//Call the rollup utility.
RollUpSummaryUtility.rollUpTrigger(fieldDefinitions, trigger.new, 'Asset', 'Contract__c', 'Contract', 'and Status != \'Inactive\' and ZARR__c > 0');
}
if(trigger.isDelete){
//Create the list of rollups we want.
list<RollUpSummaryUtility.fieldDefinition> fieldDefinitions = new list<RollUpSummaryUtility.fieldDefinition>{
new RollUpSummaryUtility.fieldDefinition('COUNT', 'ID', 'Active_Assets__c')
};
//Call the rollup utility.
RollUpSummaryUtility.rollUpTrigger(fieldDefinitions, trigger.old, 'Asset', 'Contract__c', 'Contract', 'and Status != \'Inactive\'');
}
}
Is this happening because it is being called in the if statement?
Thanks again!
Ashley
Although it seems like you might be hitting this due to the trigger on Asset calling this function and updating contacts which also fire some trigger. In this case since triggers are being fired in this manor you might want to restructure your code to avoid triggers firing recursively or update less records at a time. Maybe batch apex might be your solution here.
Hope this helps