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
Churchill19Churchill19 

20 query limiter on a Trigger

Hi All,

 

need you help with a trigger i have that is fired when the Contract.Renewal_Negotiators__c field is inserted or updated the trigger then populates the Sales_Employees__c field which is a lookup field to the User object.

 

The trigger works on a manual process but i had to put in the following code to allow me to update all records in the Contracts object : -

 

                //Not to fire Trigger if user is equal to 'Admin Name'
                if (UserInfo.getName()<> 'Admin name')

 

i am hitting the governer limits if i take off the above code... i know the logic is in correct and that i need to take this out of the for loop.

 

Problem is that i not sure how to amend my code below so i don't hit the limits... can someone help me by re-writing the code below so i don't hit the limiters?

 

Thanks.

 

Sean. 

 

 

 

 

trigger Sales_Manager_Trigger on Contract__c (before insert, before update) { for (Contract__c Contract : Trigger.new) { //Not to fire Trigger if user is equal to 'Admin Name' if (UserInfo.getName()<> 'Admin name') { Contract.Sales_Manager__c = null; List <Sales_Employees__c> arrRenNegs = new list <Sales_Employees__c>(); arrRenNegs = [select name from Sales_Employees__c where ID = :Contract.Renewal_Negotiators__c]; if (arrRenNegs.size()>0) { List <user> arrUsers = new List <user>(); arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name]; if (arrUsers.size()>0) { Contract.Sales_Manager__c = arrUsers.get(0).ID; } } } } }

 

Best Answer chosen by Admin (Salesforce Developers) 
WesNolte__cWesNolte__c

Okay let's sort this baby out. I'm sure this is more or less what you're trying to do,

 

 

trigger Sales_Manager_Trigger on BGB_Contract__c (before insert, before update) {

	Map<id,BGB_Contract__c> contracts = Map<id, BGB_Contract__c>();

    for (BGB_Contract__c bgbContract : Trigger.new)
    {
		contracts.put(bgbContract.id, bgbContract);
    }		   
	//Not to fire Trigger if user is equal to 'Sean Churchill'
	if (UserInfo.getName()<> 'Sean Churchill')

	{ 
		Map <Id, String> bseNameContractIdMap = new Map<Id, String>();
	   for(BGB_Sales_Employees__c bse: [select name from BGB_Sales_Employees__c where ID IN :contracts.keySet()]){
	   	bseNameContractIdMap.put(bse.name, bse.id);
	   }
	   
	   for(User u: [select ID from User where Name IN :bseNameContractIdMap.keyset()]){
	   	BGB_Contract__c contract = contracts.get(bseNameContractIdMap.get(u.name)); // this is the record that the triggered fired for, that matches your users name
	   	contract.sales_manager__c = u.id;
	   }
			
	}
}

 

 

For every execution of the trigger you will execute 2 SOQL queries. If this is the only trigger firing you are well within your limits. If you pass 10000000000 records to the trigger - which isn't possible - but if you could only 2 queries would execute. This solves the question originally posed in this post.

 

You also mentioned you'd like the trigger to run over 12 000 records, but you may have to batch as that limit can cause more than one type of govenor limit exception. How is the update being initialised? If you can break it into thirds you should be okay. Another very nifty feature is bulk apex, check that out here: http://salesforcesource.blogspot.com/2010/02/utilizing-power-of-batch-apex-and-async.html

 

 

All Answers

Ispita_NavatarIspita_Navatar

You need to optimize your code by bringing SOQL and DML out of your for loops.

 

 

trigger Sales_Manager_Trigger on Contract__c (before insert, before update)

{

for (Contract__c Contract : Trigger.new)

{ //Not to fire Trigger if user is equal to 'Admin Name'

if (UserInfo.getName()<> 'Admin name')

{

Contract.Sales_Manager__c = null;

List <Sales_Employees__c> arrRenNegs = new list <Sales_Employees__c>();

arrRenNegs = [select name from Sales_Employees__c where ID = :Contract.Renewal_Negotiators__c];

if (arrRenNegs.size()>0)

{

List <user> arrUsers = new List <user>();

arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name];

if (arrUsers.size()>0)

{

Contract.Sales_Manager__c = arrUsers.get(0).ID;

}

} } } }

 

You have to try and remove these SOQL out of the loop by modifying the logic.

 

 

Did this answer your question? If not, let me know what didn't work, or if so, please mark it solved.

WesNolte__cWesNolte__c

Hey

 

I'm not sure what you're doing in the second half of the trigger but the below code will move your queries out of the loop:

 

 

trigger Sales_Manager_Trigger on Contract__c (before insert, before update) { 
	List <Sales_Employees__c> arrRenNegs = new list <Sales_Employees__c>(); 
	Set<Id> contractIds = new Set<Id>();

	for (Contract__c Contract : Trigger.new) { 		
		contractIds.add(contract.renewal_negotiators__c);
	}
	
	//Not to fire Trigger if user is equal to 'Admin Name' 
	if (UserInfo.getName()<> 'Admin name') { 
		Contract.Sales_Manager__c = null; 

		arrRenNegs = [select name from Sales_Employees__c where ID IN :contractIds]; 		
		
		// I'm not sure what you're doing here when fetching the element at index[0] of arrRenNegs, it might need to change too.
		if (arrRenNegs.size()>0) { 
			List <user> arrUsers = new List <user>(); 
			arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name]; 
			if (arrUsers.size()>0) { 
				Contract.Sales_Manager__c = arrUsers.get(0).ID; 
			} 
		} 
	}
}

 

 

Cheers,

Wes

Churchill19Churchill19

Thanks to both of you...

 

In terms of the code... below I am getting the list of users and populating the Contract.Sales_Manager__c field with the name of the user

 

I have taken the you code that you did with the logic but still hitting the limiters??

 

Any Chance you could help with resolve this??? error was on line 15 column 33

 

Please...

 

Thanks.

 

 

// I'm not sure what you're doing here when fetching the element at index[0] of arrRenNegs, it might need to change too.
		if (arrRenNegs.size()>0) { 
			List <user> arrUsers = new List <user>(); 
			arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name]; 
			if (arrUsers.size()>0) { 
				Contract.Sales_Manager__c = arrUsers.get(0).ID; 
			} 

 

 

WesNolte__cWesNolte__c

Hey

 

Please can you post all of the code you're using, it doesn't seem to make sense because the code that I've posted only runs 2 queries per trigger call.

 

Wes

Churchill19Churchill19

Hi weznolte,

 

below is all the code for my trigger: -

 

trigger Sales_Manager_Trigger on Contract__c (before insert, before update) {

List <Sales_Employees__c> arrRenNegs = new list <Sales_Employees__c>();
Set<Id> contractIds = new Set<Id>();
List <user> arrUsers = new List <user>();

    for (Contract__c bgbContract : Trigger.new)
    {
    	//contractIds.add(Contract.Renewal_Negotiators__c);
    	
	   //Not to fire Trigger if user is equal to 'Sean Churchill'
       // if (UserInfo.getName()<> 'Sean Churchill')
            
                Contract.Sales_Manager__c = null;
            arrRenNegs = [select name from Sales_Employees__c where ID = :Contract.Renewal_Negotiators__c];
            
                if (arrRenNegs.size()>0)
                {
                    
                    arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name];
                    
                    if (arrUsers.size()>0)
                    {
                        Contract.Sales_Manager__c = arrUsers.get(0).ID;
                    }
                }
                
            }
    }

 It works when i manually update a single record but when i use the update function Apex Data Loader then i get a error message below: -

 

Sales_Manager_Trigger: execution of BeforeUpdate

caused by: System.Exception: Too many SOQL queries: 21

Trigger.Sales_Manager_Trigger: line 15, column 26

arrRenNegs = [select name from BGB_Sales_Employees__c where ID = :bgbContract.Renewal_Negotiators__c];

 

Line 15 column 26 is shown above after 'arrRenNegs ='

 

Thanks,

 

Sean.

WesNolte__cWesNolte__c

Hi Sean

 

If you take a look at the sample code I gave you there aren't any queries in a loop. If you copy that code you will not encounter this errors. Is there some requirement that my code does not meet? 

 

Wes

Churchill19Churchill19

Hi weznolte,

 

i tried you code but got the same error... I have amended the code can you have a look at this and see what the problem may be?

 

trigger Sales_Manager_Trigger on BGB_Contract__c (before insert, before update) {

List <BGB_Sales_Employees__c> arrRenNegs = new list <BGB_Sales_Employees__c>();
Set<Id> contractIds = new Set<Id>();


    for (BGB_Contract__c bgbContract : Trigger.new)
    {
    	//contractIds.add(bgbContract.Renewal_Negotiators__c);
    	
	   //Not to fire Trigger if user is equal to 'Sean Churchill'
       if (UserInfo.getName()<> 'Sean Churchill')
       
       {
           
                bgbContract.Sales_Manager__c = null;
            arrRenNegs = [select name from BGB_Sales_Employees__c where ID = :bgbContract.Renewal_Negotiators__c];
            
                if (arrRenNegs.size()>0)
                {
                    List <user> arrUsers = new List <user>();
                    arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name];
                    
                    if (arrUsers.size()>0)
                    {
                        bgbContract.Sales_Manager__c = arrUsers.get(0).ID;
                    }
                }
                
            }
    }

}

 the error i get is the following: -

 

Sales_Manager_Trigger: execution of BeforeUpdate

caused by: System.Exception: Too many SOQL queries: 21

Trigger.Sales_Manager_Trigger: line 17, column 26

 

Which is the same place as below...

WesNolte__cWesNolte__c
trigger Sales_Manager_Trigger on BGB_Contract__c (before insert, before update) {

List <BGB_Sales_Employees__c> arrRenNegs = new list <BGB_Sales_Employees__c>();
Set<Id> contractIds = new Set<Id>();


    for (BGB_Contract__c bgbContract : Trigger.new)
    {
    	contractIds.add(bgbContract.Renewal_Negotiators__c);
    } // close the loop here
	   //Not to fire Trigger if user is equal to 'Sean Churchill'
       if (UserInfo.getName()<> 'Sean Churchill')
       
       {
           
                bgbContract.Sales_Manager__c = null;
            arrRenNegs = [select name from Sales_Employees__c where ID IN :contractIds]; 		// Since you aren't in a loop this the first query
            
                if (arrRenNegs.size()>0)
                {
                    List <user> arrUsers = new List <user>();
                    arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name]; // No loop, so this is query number 2. You have only run 2 queries (this one and the previous) each time the trigger fires.
                    
                    if (arrUsers.size()>0)
                    {
                        bgbContract.Sales_Manager__c = arrUsers.get(0).ID;
                    }
                }
                
            }

}
Churchill19Churchill19

Thanks for your help... I have done what you have said and i get the following error?

 

"Save error: Expression cannot be assigned"

 

not sure what this means?? below is the updated code i had to re-declared BGB_contracts__c var as the bgbContract was in the loop.

 

Any ideas???

 

here the error:

 

Description	Resource	Path	Location	Type
Save error: Expression cannot be assigned	Sales_Manager_Trigger.trigger	Test/src/triggers	line 0	Force.com save problem

here the code: -

 

trigger Sales_Manager_Trigger on BGB_Contract__c (before insert, before update) {

List <BGB_Sales_Employees__c> arrRenNegs = new list <BGB_Sales_Employees__c>();
Set<Id> contractIds = new Set<Id>();


    for (BGB_Contract__c bgbContract : Trigger.new)
    {
    	contractIds.add(bgbContract.Renewal_Negotiators__c);
    }	
	   //Not to fire Trigger if user is equal to 'Sean Churchill'
       if (UserInfo.getName()<> 'Sean Churchill')
       
       { 
           
                BGB_Contract__c.Sales_Manager__c = null;
                       
            arrRenNegs = [select name from BGB_Sales_Employees__c where ID = :BGB_Contract__c.Renewal_Negotiators__c];
            
                if (arrRenNegs.size()>0)
                {
                    List <user> arrUsers = new List <user>();
                    arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name];
                    
                    if (arrUsers.size()>0)
                    {
                        BGB_Contract__c.Sales_Manager__c = arrUsers.get(0).ID;
                    }
                }
                
            }
    }

 

WesNolte__cWesNolte__c

Take this code and copy and paste it. Don't change anything. If you get an error tell me what it is.

 

 

trigger Sales_Manager_Trigger on BGB_Contract__c (before insert, before update) {

List <BGB_Sales_Employees__c> arrRenNegs = new list <BGB_Sales_Employees__c>();
Set<Id> contractIds = new Set<Id>();


    for (BGB_Contract__c bgbContract : Trigger.new)
    {
    	contractIds.add(bgbContract.Renewal_Negotiators__c);
    }	
	   
	//Not to fire Trigger if user is equal to 'Sean Churchill'
	if (UserInfo.getName()<> 'Sean Churchill')

	{ 
	   arrRenNegs = [select name from BGB_Sales_Employees__c where ID IN :contractIds]; // don't change this line. Resist the temptation.
		
			if (arrRenNegs.size()>0)
			{
				List <user> arrUsers = new List <user>();
				arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name];
				
				if (arrUsers.size()>0)
				{
					BGB_Contract__c.Sales_Manager__c = arrUsers.get(0).ID;
				}
			}
			
	}
}

 

 

Churchill19Churchill19

Hi,

 

I get the following error still after copying your copy and not changing anything: -

 

Description Resource Path Location Type
Save error: Expression cannot be assigned Sales_Manager_Trigger.trigger Test/src/triggers line 0 Force.com save problem

 

 

??

WesNolte__cWesNolte__c
trigger Sales_Manager_Trigger on BGB_Contract__c (before insert, before update) {

List <BGB_Sales_Employees__c> arrRenNegs = new list <BGB_Sales_Employees__c>();
Map<id,BGB_Contract__c> contracts = Map<id, BGB_Contract__c>();

    for (BGB_Contract__c bgbContract : Trigger.new)
    {
contracts.put(bgbContract.id, bgbContract);
    }		   
	//Not to fire Trigger if user is equal to 'Sean Churchill'
	if (UserInfo.getName()<> 'Sean Churchill')

	{ 
	   arrRenNegs = [select name from BGB_Sales_Employees__c where ID IN :contracts.keySet()];
		
			if (arrRenNegs.size()>0)
			{
				List <user> arrUsers = new List <user>();
				arrUsers = [select ID from User where Name = :arrRenNegs.get(0).Name];
				
				if (arrUsers.size()>0)
				{
					BGB_Contract__c.Sales_Manager__c = arrUsers.get(0).ID; // this is your problem line. Your not using a variable. Using my changes above you need some way to select a contract e.g. contracts.get('a bgbContract id').Sales_manager__c = arrUsers.get(0).id
				}
			}
			
	}
}
Churchill19Churchill19

Thanks for all your help with this... but it doesn't look like this trigger will work on a overnight process of an update of 12,000 records...

 

Thanks,

 

sean.

Churchill19Churchill19

Hi,

 

The problem is... we need to update an field with in the same contract record - is there any way to get a handle on each individual instance of the contract record, using your method?

 

Many thanks for all you help,

 

Sean. 

WesNolte__cWesNolte__c

Okay let's sort this baby out. I'm sure this is more or less what you're trying to do,

 

 

trigger Sales_Manager_Trigger on BGB_Contract__c (before insert, before update) {

	Map<id,BGB_Contract__c> contracts = Map<id, BGB_Contract__c>();

    for (BGB_Contract__c bgbContract : Trigger.new)
    {
		contracts.put(bgbContract.id, bgbContract);
    }		   
	//Not to fire Trigger if user is equal to 'Sean Churchill'
	if (UserInfo.getName()<> 'Sean Churchill')

	{ 
		Map <Id, String> bseNameContractIdMap = new Map<Id, String>();
	   for(BGB_Sales_Employees__c bse: [select name from BGB_Sales_Employees__c where ID IN :contracts.keySet()]){
	   	bseNameContractIdMap.put(bse.name, bse.id);
	   }
	   
	   for(User u: [select ID from User where Name IN :bseNameContractIdMap.keyset()]){
	   	BGB_Contract__c contract = contracts.get(bseNameContractIdMap.get(u.name)); // this is the record that the triggered fired for, that matches your users name
	   	contract.sales_manager__c = u.id;
	   }
			
	}
}

 

 

For every execution of the trigger you will execute 2 SOQL queries. If this is the only trigger firing you are well within your limits. If you pass 10000000000 records to the trigger - which isn't possible - but if you could only 2 queries would execute. This solves the question originally posed in this post.

 

You also mentioned you'd like the trigger to run over 12 000 records, but you may have to batch as that limit can cause more than one type of govenor limit exception. How is the update being initialised? If you can break it into thirds you should be okay. Another very nifty feature is bulk apex, check that out here: http://salesforcesource.blogspot.com/2010/02/utilizing-power-of-batch-apex-and-async.html

 

 

This was selected as the best answer
Churchill19Churchill19

Hi,

 

I have pasted your code and get the following error message when trying to save the code: -

 

Description	Resource	Path	Location	Type
Save error: unexpected token: 'Map'	Sales_Manager_Trigger.trigger	Test/src/triggers	line 3	Force.com save problem

 

any ideas??

WesNolte__cWesNolte__c
Map<id,BGB_Contract__c> contracts = new Map<id, BGB_Contract__c>();
Churchill19Churchill19

Thanks, that worked...

 

I only covering 70% of my test now but cannot get it over the required 75% is it possible for you to help below: -

 

@isTest
private with sharing class Sales_Manager_Email_Test {

static testMethod void MyTestSalesManEma()
{
    test.starttest();
    
    BGB_Contract__c testContractEmail = new BGB_Contract__c();
    
    testContractEmail.Account_Name__c = '0012000000SSw7l';
    testContractEmail.Feedback__c = 'Testing';
    testContractEmail.Renewal_Negotiators__c = 'a0H20000001oFrP';
    testContractEmail.Sold_By__c = 'a0H20000001oFrP';
    testContractEmail.Contract_Spend__c = 110;
    testContractEmail.Account_Manager_Name__c = 'a0B20000005HzDy';
    testContractEmail.Sales_Manager__c = '005S0000000WMSv';
    
    insert testContractEmail;
    
    test.stoptest();
}

}

 

 

 

 

WesNolte__cWesNolte__c

I'm guessing it's because of this line:

 

UserInfo.getName()<> 'Sean Churchill'
You need your test to not run as you. Google 'salesforce test.runas'. If you're still having issues you should start a new thread. Wes