0

Looking to bulkify this trigger. Intention was to create a set of ID's that are of a certain record type, and then pass those into a method that will then check for empty fields. Didn't post all of the code for the TriggerHandler because there are other errors but I want to solve this issue first. Ultimately what I want to do is check each Contact record that is updated at a certain time, check to see if it has any Account/Contact relationship with a certain role, then check the Contact address to make sure it is complete.

Error: "Method does not exist or incorrect signature: void IsPricingLetter(List) from the type ContactTriggerHandler"

Trigger

trigger ContactTrigger on Contact (before update) {
    if(trigger.isbefore){
        if(trigger.isupdate){
            //loop through trigger.new to see if it's a US record type
            List<Contact> c = new List<Contact>();
            for(Contact USContact : Trigger.new){
                String recordtypename = 'CRM Contact US';
                    if(USContact.recordtype.name==recordtypename){
                        c.add(USContact.id);
                    }//End if statement    
            }//End for loop
            ContactTriggerHandler.IsPricingLetter(c);
                            }//End If IsUpdate          
                   }//End If IsBefore
   }//End Class

Trigger Handler

public class ContactTriggerHandler {
    public static void IsPricingLetter(List<Contact> con){
        //Get list of relationship records that contain Pricing Letters role on the Contact ID being triggered.
        List<Contact> conNew = new List<Contact>();
        for (Contact USList : con){       
            conNew.add(USList);
        }

This is the rest of the trigger handler, but this is incorrect. You can use this to get a better understanding of what I am looking for.

         for(AccountContactRelation c : [SELECT ContactId FROM accountcontactrelation WHERE isActive=true 
                                        AND roles INCLUDES ('Pricing Letters') AND Contactid IN :conNew.id]){
//If triggering Contact ID is present, check for missing mailing address components or missing email address.
         if(conNew.MailingStreet==null){
            conNew.MailingStreet.addError('Mailing Street on a Pricing Letter Contact cannot be null.'); 
                                }//End If Mailing Street
        if(conNew.MailingCity==null){
            conNew.MailingCity.addError('Mailing City on a Pricing Letter Contact cannot be null.');   
                                 }//End If Mailing City
        if(conNew.MailingPostalCode==null){
            conNew.MailingPostalCode.addError('Mailing City on a Pricing Letter Contact cannot be null.');    
                                 }//End If Mailing Postal
        if(conNew.MailingState==null){
            conNew.MailingState.addError('Mailing State on a Pricing Letter Contact cannot be null.');
                                 }//End If Mailing State
        if(conNew.MailingCountry==null){
            conNew.MailingCountry.addError('Mailing Country on a Pricing Letter Contact cannot be null.');   
                                 }//End If Mailing Country
        if(conNew.Email==null){
            conNew.Email.addError('Email Address on a Pricing Letter Contact cannot be null.');   
                                 }//End If Mailing Country
                    }//End For Loop
      
    }//End IsPricingLetter Method
}//End Class

Thanks in advance.

6
  • 2
    It's not immediately clear what the issue is here. Passing a Set<Id> to a method is done the same way as you would pass any other type to a method. If you're getting an error message, you should edit your question to include the full text of the error, verbatim (if you try to paraphrase, you're almost guaranteed to leave out important information).
    – Derek F
    Feb 2, 2023 at 18:31
  • On a second reading, it looks like the issue isn't with passing the Set<Id>, but rather in how you're using it. The Id is not the SObject itself, so you can't do for(SObject obj : myIdSet). Typically in trigger handlers, you'll see people passing in Lists or Maps of SObjects (not just a collection of the Ids). This is mainly to break the dependency on trigger context variables for testing. In your case though, changing your code to pass/accept a List<Contact> will let you use .addError() later on.
    – Derek F
    Feb 2, 2023 at 18:40
  • Noted on the id issue, and apologies. Error: "Method does not exist or incorrect signature: void IsPricingLetter(Set) from the type ContactTriggerHandler" Feb 2, 2023 at 18:50
  • I get the same error when I change it to a List Feb 2, 2023 at 18:53
  • 1
    Please edit your question to add additional information. Comments are temporary (at least in theory), and it's harder to pick out information (due to limits on length and formatting). Also, double-check that ContactTriggerHandler has the code you think it does in the org that you're seeing this error in (open the class in the developer console for that specific org). At the moment, this smacks of "accidentally forgot to deploy the updated code to this org".
    – Derek F
    Feb 2, 2023 at 19:09

1 Answer 1

1

First, a quick note. "Bulkification" is just a short way of saying "there are no queries or DML inside of loops".

Collections (Lists, Sets, and Maps) get passed to methods the same way as any other data type. You need to define the parameter in the method signature

public class MyClass{
    public static void myStaticMethod(List<Contact> newList){
        // do work
    }
}

and then call the method and pass it data of the same (or a compatible) type

public class OtherClass{
    public void otherMethod(){
        List<Contact> contactList = new List<Contact>();

        MyClass.myStaticMethod(contactList);
    }
}

As simple as that is, that's 90% of it right there

  • Making sure the class name is correct
  • Making sure the method name is correct (and that you're using the class name to access static methods, or an instance of the class to access non-static methods)
  • Passing in an argument of the appropriate type

If you've checked all of that, and are still getting an error, then the usual suspects are:

  • You haven't deployed a change to the code to the org you're working in (i.e. you've made a change in sandbox 1, and are trying to use that change in sandbox 2. The change hasn't been deployed to sandbox 2 yet)
  • You have some name shadowing going on. Either you have a variable named the same as the class, or you have a separate Apex class somewhere named Contact. Apex is largely case-insensitive, so contactTriggerHandler and CoNtAcTtRiGgErHaNdLeR are treated as the same.

Beyond that, there are some issues I see with your code

Not all of these are errors, and they're not likely to get you past the error you've reported, but they are worth mentioning (and fixing)

  • Bad variable names
    • Single letter variable names make it harder to understand and maintain code (what does "c" mean in this context?). You should use descriptive names like newContacts or contactIdSet. You'll thank yourself down the line for doing this.
  • Logic in your trigger
    • Logic inside of a trigger is logic that's difficult to test, because you can't execute it independently (it's always executed as a result of DML, which will invariably cause more code to be executed than just the thing you're trying to test). Ideally, your trigger should only get you into your trigger handler. e.g.
      trigger ContactTrigger on Contact (before update){
           switch on Trigger.operationType {
               when System.TriggerOperation.BEFORE_UPDATE { ContactTriggerHandler.beforeUpdate(trigger.old, trigger.new); }
           }
      }
      
      The implication being that the job of filtering the Contacts based on recordType would fall to the beforeUpdate() method
  • Trying to access "related data" from a Trigger Context Variable
    • If you need more than one . to access data, it's "related data". Trigger Context Variables only contain data on the triggered object (and no "related data"), so USContact.recordtype.name will be null, guaranteed, 100% of the time. You need to do one of:
      • Pull the data into your Contact record itself via a formula field
      • Explicitly query for that data
      • Use SObject Describe info to get the recordTypeId to compare against (e.g. Schema.SObjectType.Contact.getRecordTypeInfosByName().get('CRM Contact US').getRecordTypeId();
  • You changed the type of the collection you're passing in, but not the data being added to it
    • c.add(USContact.id); is now a syntax error. c is not a List/Set of Ids, it's a List of Contacts. At the very least, you need to drop the .id part
  • Trying to get the id of a collection
    • conNew.id is wrong because conNew is a List, and lists do not have an id property (or really any properties, collections just have methods). Salesforce is smart enough to be able to take a List<SObject> used in a variable bind to an Id field, so ContactId IN :conNew would be sufficient

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .