2

I have a flow that generates an encrypted token for new Campaign Member records. This works perfectly fine for creating one record at a time. When I try to create 188 campaign members I get error An Apex error occurred: System.LimitException: ued:Too many DML statements: 151. I'm not using any DML statements (to my knowledge: update, insert, create, upsert, delete) in the apex class so I'm not sure why I'm getting this limit exception. I'm putting the records in a collection variable in the flow so if the DML error were to occur it should occur in the update part of the flow, not in the apex class.

Any help is greatly appreciated. I'm currently working to put this into a trigger as I don't think this is possible with flow, although it should be.

enter image description here

Apex Class

//called from Flow
public class encrypt 
{
    @InvocableMethod
    public static List<List<CampaignMember>> CmId(List<CampaignMember> ListCampaignMembers)
    {
        //String encryptedToken2 = ued.UserCryptoHelper.doEncryptWithUrlEncoding(encryptedToken, 'UTF');
        for(CampaignMember cm : ListCampaignMembers)
        {
            Guest_User_Encryption__c gue = [select Site_Name__c, Guest_User_ID__c from Guest_User_Encryption__c where Site_Name__c =: cm.Site_Name__c];
            String encryptedToken = System.EncodingUtil.urlEncode(ued.UserCryptoHelper.doEncrypt(cm.id, gue.Guest_User_ID__c),'UTF-8');
            cm.Encrypted_Record_Id__c = encryptedToken;
        }
        List<List<CampaignMember>> returnList = new List<List<CampaignMember>>();
        returnlist.add(listCampaignMembers);
        return returnList;
    }
}
2
  • What does this class/method contain: ued.UserCryptoHelper.doEncrypt ? Commented May 14, 2021 at 1:24
  • @CasparHarmer This is a Salesforce Lab product. I couldn't find the source for it, but I found the package itself, and the culprit.
    – sfdcfox
    Commented May 14, 2021 at 2:26

1 Answer 1

6

First, your code isn't properly bulkified. Even if you didn't get a DML error where you did, you should still hit the SOQL limit for having a query inside a loop.

Second, keep in mind that flows are bulkified automatically. You must not return all the campaign members from the input into an element of the output. This is injecting parallel records into the wrong flows (namely, the first one). I'm surprised you didn't get a different runtime error, since the input list of 188 members was being mapped to an output of just 1.

Your bulkified, correctly mapped output should look like:

public class encrypt {
    @InvocableMethod public static List<CampaignMember> cmId(List<CampaignMember> campaignMembersIn) {
        Map<String, Guest_User_Encryption__c> encryptions = new Map<String, Guest_User_Encryption__c>();
        for(CampaignMember campaignMember: campaignMembersIn) {
            encryptions.put(campaignMember.Site_Name__c, null);
        }
        for(Guest_User_Encryption__c guestUserEncryption: [SELECT Site_Name__c, Guest_User_ID__c FROM Guest_User_Encryption__c WHERE Site_Name__c = :encryptions.keySet()]) {
            encryptions.put(guestUserEncryption.Site_Name__c, guestUserEncryption);
        }
        for(CampaignMember campaignMember: campaignMembersIn) {
            Guest_User_Encryption__c gue = guestUserEncryption.get(campaignMember.Site_Name__c);
            campaignMember.Encrypted_Record_Id__c = EncodingUtil.urlEncode(ued.UserCryptoHelper.doEncrypt(campaignMember.Id, gue.Guest_User_ID__c),'UTF-8');
        }
        return campaignMembersIn;
    }
}

Third, I installed this package, which I presume you're using, and tested the following code:

for(Integer i = 0; i < 200; i++) {
    ued.UserCryptoHelper.doEncrypt('hello world');
}

To which I get:

FATAL_ERROR|System.LimitException: ued:Too many DML statements: 151

Checking the logs, I see it's writing to some custom setting data:

DML_BEGIN|[106]|Op:Update|Type:ued__User_Encryption_Settings__c|Rows:1
DML_END|[106]

This occurs for every single call, ultimately causing the DML exception you see.

This library is not suitable for your intended purpose. You'll need to find a library that supports bulk encryption, does not write to the database, or roll your own encryption.

10
  • I knew it!!!!!! Suspected it was it, but yeah, didn't spend any time looking for it. Commented May 14, 2021 at 2:32
  • 1
    @CasparHarmer Yeah, you know me. I can't resist a good mystery.
    – sfdcfox
    Commented May 14, 2021 at 2:34
  • Yep, good strategy - I was going to wait for the asker to tell me the package - too lazy Commented May 14, 2021 at 2:37
  • Thanks for solving this. I actually ended up changing the custom setting to custom metadata to avoid the soql limit but still get the dml limit even in trigger(from the package as you mentioned). Not sure how to 'roll your own encryption'. The package is User Encryption Decryption, this how Salesforce wants you to allow the Guest User to update their record after the security change they released.
    – ThatGuy
    Commented May 14, 2021 at 14:19
  • @theNewGuy This library isn't meant for bulk insert/updates. If you absolutely need it, and it needs to be this class, you're going to have to update the records asynchronously in batches of up to 100 or so.
    – sfdcfox
    Commented May 14, 2021 at 14:30

You must log in to answer this question.

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