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
Gabe Rothman 8Gabe Rothman 8 

Can someone help me bulkify this class?

I've been trying to do a bulk update of records using the data loader and I keep getting the following error:
"rfp: execution of BeforeInsert
caused by: System.QueryException: List has more than 1 row for assignment to SObject
Class.setRfpOwner.setOwners: line 15, column 1
Trigger.rfp: line 4, column 1 "

After looking at my code and the records I'm querying, I the query in line 15 of my service class should only yield one result, which leads me to believe that my service class is somehow not bulk safe. Can anyone point me in the right direction:

Trigger:
trigger rfp on RFP_Response__c (before insert, before update) {

    if(trigger.isBefore && trigger.isInsert){
        setRfpOwner.setOwners(trigger.new);
        rfpKwBuilder.buildKeyWords(Trigger.new);
    }
    if(trigger.isBefore && trigger.isUpdate){
        if(checkRecursive.flag == true){
            rfpKwBuilder.buildKeyWords(Trigger.new);
            for(RFP_Response__c rfp : Trigger.new){
                RFP_Response__c oldRfp = Trigger.oldMap.get(rfp.Id);
                if(oldRfp.Response__c != rfp.Response__c){
                    setResponseToggle.toggleResponse(trigger.new);      
                }                              
            }
            for(RFP_Response__c rfp : Trigger.new){
                RFP_Response__c oldRfp = Trigger.oldMap.get(rfp.Id);
                if(oldRfp.Category__c != rfp.Category__c){
                    setRfpOwner.setOwners(trigger.new);
                }                              
            }            
            
        } 
        checkRecursive.flag = false;
    }    
    
}

Class:
public class setRfpOwner {

    public static void setOwners(list<RFP_Response__c> rfpUpdateList){
        List<String> listCategories = new List<String>();

        for (RFP_Response__c rfp : rfpUpdateList) {
            if(rfp.Category__c == null){
                return;
            }
            if(rfp.Category__c != null){
                listCategories.add(rfp.Category__c);              
            }
        }
            RFP_Owner_Mappings__c mapping = [SELECT Name, RFP_Category_Owner__c, RFP_Category_Backup_Owner__c,RFP_Category_Owner__r.Email__c,RFP_Category_Backup_Owner__r.Email__c 
                                            FROM RFP_Owner_Mappings__c  
                                            WHERE Name IN :listCategories];
            for (RFP_Response__c rfp2 : rfpUpdateList){
                if(rfp2.Category__c == mapping.Name ){
                    rfp2.RFP_Category_Owner__c = mapping.RFP_Category_Owner__c;
                    rfp2.RFP_Category_Backup_Owner__c  = mapping.RFP_Category_Backup_Owner__c ;
                    rfp2.Category_Owner_Email__c = mapping.RFP_Category_Owner__r.Email__c;
                    rfp2.Category_Backup_Owner_Email__c  = mapping.RFP_Category_Backup_Owner__r.Email__c ;                    
                }          
            }
        
    }
    
}



 
Best Answer chosen by Gabe Rothman 8
Paul_BoikoPaul_Boiko
This error message means that your query returns more than 1 record, so you need to use list of RFP_Reponse__c sObjects and then put them in Map with category (Name) as a key and record as a value and then use map to get mapping by category:
 
List<RFP_Owner_Mappings__c> mappings = [SELECT Name, RFP_Category_Owner__c, RFP_Category_Backup_Owner__c,RFP_Category_Owner__r.Email__c,RFP_Category_Backup_Owner__r.Email__c 
                                            FROM RFP_Owner_Mappings__c  
                                            WHERE Name IN :listCategories];
Map<String, RFP_Owner_Mappings__c> ownerByCategoryNameMap = new Map<String, RFP_Owner_Mappings__c>();
for ( RFP_Owner_Mappings__c mapping: mappings ) {
     ownerByCategoryNameMap.put( mapping.Category__c , mapping);
}

for (RFP_Response__c rfp2 : rfpUpdateList){ 
     RFP_Owner_Mappings__c mapping = ownerByCategoryNameMap.get( rfp2.Category__c );
      rfp2.RFP_Category_Owner__c = mapping.RFP_Category_Owner__c; 
      rfp2.RFP_Category_Backup_Owner__c = mapping.RFP_Category_Backup_Owner__c ; 
      rfp2.Category_Owner_Email__c = mapping.RFP_Category_Owner__r.Email__c; 
      rfp2.Category_Backup_Owner_Email__c = mapping.RFP_Category_Backup_Owner__r.Email__c ; 
} 

 

All Answers

Gabe Rothman 8Gabe Rothman 8
Follow up note:
This code works perfectly when processing one record at a time -- further evidence that it's not bulk safe.
Paul_BoikoPaul_Boiko
This error message means that your query returns more than 1 record, so you need to use list of RFP_Reponse__c sObjects and then put them in Map with category (Name) as a key and record as a value and then use map to get mapping by category:
 
List<RFP_Owner_Mappings__c> mappings = [SELECT Name, RFP_Category_Owner__c, RFP_Category_Backup_Owner__c,RFP_Category_Owner__r.Email__c,RFP_Category_Backup_Owner__r.Email__c 
                                            FROM RFP_Owner_Mappings__c  
                                            WHERE Name IN :listCategories];
Map<String, RFP_Owner_Mappings__c> ownerByCategoryNameMap = new Map<String, RFP_Owner_Mappings__c>();
for ( RFP_Owner_Mappings__c mapping: mappings ) {
     ownerByCategoryNameMap.put( mapping.Category__c , mapping);
}

for (RFP_Response__c rfp2 : rfpUpdateList){ 
     RFP_Owner_Mappings__c mapping = ownerByCategoryNameMap.get( rfp2.Category__c );
      rfp2.RFP_Category_Owner__c = mapping.RFP_Category_Owner__c; 
      rfp2.RFP_Category_Backup_Owner__c = mapping.RFP_Category_Backup_Owner__c ; 
      rfp2.Category_Owner_Email__c = mapping.RFP_Category_Owner__r.Email__c; 
      rfp2.Category_Backup_Owner_Email__c = mapping.RFP_Category_Backup_Owner__r.Email__c ; 
} 

 
This was selected as the best answer
Gabe Rothman 8Gabe Rothman 8

Thanks for the response! I've updated the class below per your suggestion , and it works on single record processing, but I'm the getting the following error in bulk processing: 

"rfp: execution of BeforeInsert caused by: System.NullPointerException: Attempt to de-reference a null object
Class.setRfpOwner.setOwners: line 24, column 1
Trigger.rfp: line 4, column 1" 

public class setRfpOwner {

    public static void setOwners(list<RFP_Response__c> rfpUpdateList){
        List<String> listCategories = new List<String>();

        for (RFP_Response__c rfp : rfpUpdateList) {
            if(rfp.Category__c == null){
                return;
            }
            if(rfp.Category__c != null){
                listCategories.add(rfp.Category__c);              
            }
        }
        List<RFP_Owner_Mappings__c> mappings = [SELECT Name, RFP_Category_Owner__c, RFP_Category_Backup_Owner__c,RFP_Category_Owner__r.Email__c,RFP_Category_Backup_Owner__r.Email__c 
                                                    FROM RFP_Owner_Mappings__c  
                                                    WHERE Name IN :listCategories];
        Map<String, RFP_Owner_Mappings__c> ownerByCategoryNameMap = new Map<String, RFP_Owner_Mappings__c>();
        for ( RFP_Owner_Mappings__c mapping: mappings ) {
             ownerByCategoryNameMap.put( mapping.Category__c , mapping);
        }
        
        for (RFP_Response__c rfp2 : rfpUpdateList){ 
              RFP_Owner_Mappings__c mapping = ownerByCategoryNameMap.get( rfp2.Category__c );
              rfp2.RFP_Category_Owner__c = mapping.RFP_Category_Owner__c; 
              rfp2.RFP_Category_Backup_Owner__c = mapping.RFP_Category_Backup_Owner__c ; 
              rfp2.Category_Owner_Email__c = mapping.RFP_Category_Owner__r.Email__c; 
              rfp2.Category_Backup_Owner_Email__c = mapping.RFP_Category_Backup_Owner__r.Email__c ; 
        } 
        
    }
    
}

Any suggestions?
 
Gabe Rothman 8Gabe Rothman 8
bump
Paul_BoikoPaul_Boiko
I think you need to make sure that you have records in RFP_Owner_Mappings__c for all categories that you import. Looks like you import category that does not exist in your mapping. You can also add if statement like this:
for (RFP_Response__c rfp2 : rfpUpdateList){ 
	RFP_Owner_Mappings__c mapping = ownerByCategoryNameMap.get( rfp2.Category__c ); 
	//if mapping is found update fields from mapping 
	if ( mapping != null ) {
		rfp2.RFP_Category_Owner__c = mapping.RFP_Category_Owner__c; 
		rfp2.RFP_Category_Backup_Owner__c = mapping.RFP_Category_Backup_Owner__c ; 
		rfp2.Category_Owner_Email__c = mapping.RFP_Category_Owner__r.Email__c; 
		rfp2.Category_Backup_Owner_Email__c = mapping.RFP_Category_Backup_Owner__r.Email__c ; 
	// if mapping is not found do something else ( may be populate some default values )
	} else {
		
    }
}
You need to add code to do somthing when mapping is not found. You may want to send email or populate some default values. That's up to you.


 
Gabe Rothman 8Gabe Rothman 8
Perfect! Thanks again!