function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
naresh johnnaresh john 

How to handle soql governor limits

HI every one,

 

    I have csv records import functionality in my application. While importing records I am getting this visualforce error.

 

System.LimitException: CnP:Too many SOQL queries: 101

 

 

Trigger.CnP.addCorresCont: line 30, column 34

 

Can any one please let me know how to handle governor limits so that my import functionality  may work well. 

alexbalexb

It depends. Did you add something recently and are just now testing it? If so, you probably didn't optimize your SOQL calls. I get this error when I structure my trigger wrong. A common reason for getting the 'too many SOQL calls' exception is because you are placing a SOQL query inside a loop. This is a big no-no because it can very easily get out of control. A best practice for writing triggers is to gather all the data from the database at the beginning of the trigger, sort it into data structures, then access the data structures later in the trigger (instead of making SOQL queries). You should be able to do most triggers with just a few SOQL queries.

SteveBowerSteveBower

In seems like you have a Trigger which wasn't written to handle Bulk records.

 

For example:  If a Trigger is invoked with a few thousand records in it and the trigger logic is something like:

 

for (CnP a_CnP: trigger.new) {

    ....

   x = [select blah blah from some object for some reason]

 

Then your trigger is executing a SQL query for each record in the trigger.  So, it's easy to blow past the limit.

 

There are ways to write Apex trigger code (see  http://www.salesforce.com/us/developer/docs/apexcodepre/index.htm and look under Apex Design Patterns for a discussion on Bulk processing.) to reduce the number of Queries.

 

However it takes more work to do it that way and many triggers out there have been written with the assumption that there will be just one record in the trigger invocation... little time bombs waiting to explode on you.

 

 

You could find this trigger in the Setup->Develop->Triggers section Trigger.CnP.addCorresCont: and post the code and perhaps we can confirm that that's the situation.

 

If you have the permissions, you could go to the Trigger and deactivate it, then do your insert and then reactivate it... however, in theory the trigger was written to support your business rules and deactivating it is probably bypassing something that you want.   So, you have to examine that.

 

Best, Steve.

 


 

naresh johnnaresh john

HI Steve,

 

     Thanks for the reply. I am pasting my trigger code here.

 

 

trigger addCorresCont on CnP_Transaction__c (before insert, after insert) {
    if(trigger.isBefore){
        List<Account> accounts = new Account[0];
        List<Contact> contacts = new Contact[0];
    //    List<CnPRecurring__c> recurrings = new  CnPRecurring__c[0];
        
        Integer isAcc;
        isAcc = 0;
        Integer isCon;
        isCon = 0;
        Integer isRec;
        isRec = 0;
        
        for (CnP_Transaction__c c : Trigger.new) {
            if(c.bSource__c == 2){ // the source is coming from Import so execute this trigger.
                
                Account[] ac = [select Name from Account where name = :c.Organization_Name__c LIMIT 1];
                if(ac.size()==0){
                    accounts.add(new Account(Name = c.Organization_Name__c));    
                    isAcc = 1;
                }  
            }
         }
         if(isAcc != 0)
             insert accounts;
   
         for (CnP_Transaction__c c : Trigger.new) {
            if(c.bSource__c == 2){ // the source is coming from Import so execute this trigger.   
            
              Account[] accchk = [select Id, Name from Account where Name = :c.Organization_Name__c LIMIT 1];
                if(accchk.size() != 0)
                    c.Account__c = accchk[0].Id;
                      
                Contact[] con = [select Name from Contact where Email = :c.Email__c LIMIT 1];
                if(con.size()==0){
                    contacts.add(new Contact(firstname = c.first_name__c, lastname = c.last_name__c, Email = c.Email__c, 
                                Phone = c.Phone__c, MailingStreet = c.Address1__c, Otherstreet = c.Address_2__c, 
                                MailingCity = c.City__c, MailingState = c.State__c,MailingPostalCode= c.Zip_Code__c,accountid = c.Account__c));    
                    isCon = 1;
                }  
                  
            } 
         }       
         if(isCon != 0)
             insert contacts;
         
         for (CnP_Transaction__c c : Trigger.new) {
            if(c.bSource__c == 2){ // the source is coming from Import so execute this trigger.   
                Contact[] concchk = [select Id, Name from Contact where Email = :c.Email__c LIMIT 1];
                if(concchk.size() != 0)
                    c.Contact__c = concchk[0].Id;
             }
         }
     }  
   
     if(trigger.isAfter){
        List<Opportunity> donations = new Opportunity[0];
        List<CnPRecurringTransaction__c> recuringtrans = new CnPRecurringTransaction__c[0];
        date dt;
        datetime dtm;
        Integer isDons;
        Integer isRec;
        isDons = 0;
        String Dstage;
        String ordNumber;
        String oId;
        String rId;
        
        for (CnP_Transaction__c c : Trigger.new) {
            if(c.bSource__c == 2){ // the source is coming from Import so execute this trigger.
               Account acchk = [select Id, Name from Account where Name= :c.Organization_Name__c LIMIT 1];
              // CnPRecurring__c rec = [select Id, Name,OrderNumber__c, Installments__c from CnPRecurring__c where OrderNumber__c = :c.Name];
               if(c.Donation_Stage__c == '')
                   Dstage = 'Posted';
               else
                   Dstage = c.Donation_Stage__c;
                         
               dtm = c.TransactionDate__c;
               dt = Date.newInstance(integer.valueOf(dtm.year()),integer.valueOf(dtm.month()),integer.valueOf(dtm.day()));
              
               if(c.Name == '')
                   ordNumber = c.Name;  
               else
                   ordNumber = c.Id;
               oId = c.Id;
               
               Opportunity[] dons = [select Name from Opportunity where CnP_OrderNumber__c = :ordNumber];
              // CnPRecurringTransaction__c[] rectrans = [Select  Name,InstallmentNumber__c,Recurring_Transaction__c,TransactionId__c from CnPRecurringTransaction__c where Id =:ordNumber];
                 if(dons.size()==0){  
                     if(oId == '')
                         continue;
                     else{                         
                         donations.add(new Opportunity(Name = c.Donation_Name__c,Amount = c.Amount__c,TotalOpportunityQuantity = c.Quantity__c,
                                                      StageName = Dstage, CloseDate = dt,accountid=acchk.Id,CnP_OrderNumber__c = ordNumber)); 
                         isDons = 1;
                     }                           
                 } 
               /*   if (rectrans.size() == 0){
                  if(oId == '')
                         continue;
                     else{       
                   rectrans.add(new CnPRecurringTransaction__c(Name = 'xx',InstallmentNumber__c = rec.Installments__c, Recurring_Transaction__c = rec.Name,TransactionId__c=c.Name ));
                     isRec =1;
                   }
                   }*/
            } 
            
        }
   
        
        if(isDons != 0)
                 insert donations;   
                 
     //  if(isRec!= 0)
        //       insert recuringtrans;       
     }
 }

 

Can you please help with governor limits of soql.

 

Thanks,

naresh

 

SteveBowerSteveBower

Yeah... so, line 30 is the Select statement in this construct:

 

     for (CnP_Transaction__c c : Trigger.new) {
            if(c.bSource__c == 2){ // the source is coming from Import so execute this trigger.   
            
              Account[] accchk = [select Id, Name from Account where Name = :c.Organization_Name__c LIMIT 1];
                if(accchk.size() != 0)

 

pretty much exactly what should not be done since the Import can have lots of records. Just poor code.

 

If you're using the Apex Data Loader I think you can go to the "Settings" Menu, and the first option is the Batch Size.  You could try setting it to "1" and running your import... that way each transaction of the load would just have one record, however I have no idea how many records you're trying to do and if this would cause you to blow away other limits.

 

Just looking at it quickly, there are no good answers other than re-writing it to be bulk safe.

 

Best, Steve.

 

p.s. Also, it's not just that statement, the same faulty construct is used throughout the code.

 

 

 

naresh johnnaresh john

HI Steve thanks for the reply.

 

    We are not using apex data loader to import the records. We are importing the csv file through apex code only.

Can you please let me know how to resolve this issue.

 

 

Thanks,

Naresh B

SteveBowerSteveBower

There are several paths to take depending on your needs.  For example, if this is a one-time load, then why not try using the data loader w/ a reduced batch size.   If it's ongoing, then how many records are there in each load?   Perhaps this should be done w/ a batch job which has different limits, etc.   No matter how you slice it, this is a poorly done trigger that should be rewritten unless you're sure that there will always be a small number of records (which obviously isn't the case now).

 

If you're being sent the CSV file and you have some other code somewhere that inserts the CnP_Transactions__c records, then perhaps *that* code could be modified to only insert one record at a time, but use @future so that it doesn't hit limits?

 

I'm not sure what sort of answer you're looking for, as it depends on what your needs are.     Clearly the *best* answer is to rewrite this to be bulk-safe.    Best, Steve.

 

Pradeep_NavatarPradeep_Navatar

This error message hints that you are trying to access more than 100 SOQL query that reached the governor limit. If you face such kinds of problem check few lines in your code that you may be writing any SOQL query in a loop so avoid this SOQL in loop.

 

            below is the sample code to implement bulk handling-

            Lets say you have trigger on Opportunity which will insert records in another object when Stage reaches Closed Won

            trigger opp on Opprtunity(after update)

            {

                        List<Object__c> newRecordList = new List<Object__c>();

                        for(Opportunity o: Trigger.new)

                        {

                                    if(o.StageName = = 'Closed Won')

                                    {

                                                Object__c ob = new Object__c(name = o.name, other fields);

                                                insert ob; // You may insert here but it will reach governor limit so avoid this and add all the record in a list and outside the loop insert them.

                                                newRecordList.add(ob);

                                    }

                        }

                        if(newRecordList.size() > 0)

                        {

                                    insert newRecordList; // This is the way to implement the bulk insert without hiting governor limit.

                        }

            }