0

New to Apex and code in general so I would appreciate any recommendation on how I´m approaching this problem.

My Lead Object has a custom field utm_content__c that will hold as value the Id of the campaign it should be related to.

So basically whenever a lead is updated and the custom field utm_content__c is not null it should trigger an apex class that creates a CampaignMember for that lead in that campaign.

Before creating the CampaignMember I would like to check if it already exists. and get a list of those existing records.

That is very easy with flows using the Get element since every lead goes throug a single interview but I understand Apex Classes work with a list of Leads being updated at the same time. And it´s not recommended to perform DML actions inside for loops.

So would this approach be ok? It works but idk if there would be an easier way to get the same result.

public class crea_miembro {

public static list<CampaignMember> nuevoMiembro (List<Lead> leadsNew){
List<CampaignMember> members = new List<CampaignMember>();
Map<Id, String> partners = new Map<Id, String>();
Set<Id> LeadIds = new Set<Id>();
List<String> CampIds = new List<String>();
List <CampaignMember> allmatchingmembers = new List<CampaignMember>();

    for(Lead leadActual:leadsNew){
        partners.put(leadActual.Id, leadActual.utm_content__c);
        LeadIds.add(leadActual.Id);
        CampIds.add(leadActual.utm_content__c);
    }

 //Queries all campaignmembers based on all Lead Ids and all CampaignIds

allmatchingmembers.addAll([SELECT Id, LeadId, CampaignId FROM Campaignmember WHERE LeadId IN:LeadIds AND CampaignID IN: CampIds]);


 //Keeps only the Campaign Member that share same LeadId and CampaignId.

    for(Campaignmember member:allmatchingmembers){
        if(member.CampaignId==partners.get(member.LeadId)){
            members.add(member);
        }
    }

    for(Campaignmember imprime: members){
        System.debug(imprime.Id);
    }    
    
    return members;
   

}

}

1

1 Answer 1

1

At first glance, your code is a lot more work than it needs to be. If we use Trigger.newMap instead of Trigger.new, we don't need the partners map. Consequently, we can dramatically reduce your code to just:

public class crea_miembro {
  public static list<CampaignMember> nuevoMiembro (Map<Id, Lead> newLeadMap){
    Set<Id> campaignIds = new Set<Id>();
    for(Lead record: newLeadMap.values()) {
      campaignIds.add(record.udm_content__c);
    }
    CampaignMember[] results = new CampaignMember[0];
    for(CampaignMember member:[SELECT LeadId, CampaignId FROM CampaignMember WHERE LeadId = :newLeadMap.keySet() AND CampaignId = :campaignIds]) {
      if(newLeadMap.get(member.LeadId).udm_content__c == record.CampaignId) {
        results.add(member);
      }
    }
    return results;
  }
}

You're right to be concerned about performance. In theory, if you have 200 leads with 200 campaigns, you end up with 40,000 potential campaign members. If you wanted a very specific list of targeted records, you could do this instead:

public class crea_miembro {
  public static list<CampaignMember> nuevoMiembro (List<Lead> newLeads){
    String[] filters = new String[0];
    for(Lead record: newLeads) {
      filters.add('CampaignId = \'' + record.udm_content__c +'\'' + ' AND LeadId = \'' + record.Id+'\'');
    }
    return (CampaignMember[])Database.query('SELECT LeadId, CampaignId FROM CampaignMember WHERE ('+String.join(filters, ') OR (') + ')');
  }
}

This skips all the checks we need to make and reduces the number of returned elements to at most 200. The only real downside is having to deal with dynamic Apex. If there's a typo, you won't know until you try to run the code.

4
  • Worth also mentioning that SOQL queries have a maximum length. The clause for each campaign member is something like 80 characters, but at least there will be at most 200 of these clauses so something like 16000 characters. Just make sure the over all SOQL isn't more than the max (no risk here, but mentioned for the general perspective). See the docs.
    – Phil W
    Commented Nov 26, 2023 at 18:04
  • @PhilW The 100k limit for SOQL queries only applies to the API, not Apex. I have constructed queries that exceed 250k characters and more without running into that error.
    – sfdcfox
    Commented Nov 26, 2023 at 18:24
  • I never tested the length limit through apex and the docs are not obviously linked to only the REST API. This is one that needs the docs clarified it seems.
    – Phil W
    Commented Nov 26, 2023 at 19:05
  • @PhilW I mean "the" API, such as REST, SOAP, Tooling, Bulk, etc. Anywhere you can run SOQL directly. Apex alone plays by different rules than the rest of the system. I once heard that the SOQL/SOSL developer guide is geared for API developers, not Apex developers. Specific exceptions to Apex, etc are located in the relevant developer docs.
    – sfdcfox
    Commented Nov 26, 2023 at 19:23

You must log in to answer this question.

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