mitchspano / apex-trigger-actions-framework

A framework for partitioning, ordering, and bypassing trigger logic for applications built on Salesforce.
Apache License 2.0
503 stars 156 forks source link

Problem with After Update query #81

Closed g1b3r closed 2 years ago

g1b3r commented 2 years ago

Expected Behavior

Trigger should works

Actual Behavior

AccountTrigger: execution of AfterUpdate caused by: System.TypeException: TA_Account_After_Update_Queries does not have a no-arg constructor (System Code) Class.MetadataTriggerHandler.executeActions: line 190, column 1 Class.MetadataTriggerHandler.afterUpdate: line 40, column 1 Class.TriggerBase.run: line 81, column 1 Trigger.AccountTrigger: line 17, column 1

Steps to Reproduce the Problem

1. 1. 1.

Specifications

`public with sharing class TA_Account_After_Update_Queries { private static TA_Account_After_Update_Queries instance;

private TA_Account_After_Update_Queries() {        
}

public static TA_Account_After_Update_Queries getInstance() {
    if (TA_Account_After_Update_Queries.instance == null) {
        TA_Account_After_Update_Queries.instance = new TA_Account_After_Update_Queries();
    }
    return TA_Account_After_Update_Queries.instance;
}
public Map<Id, Case> afterCaseMap { get; private set; }

public class Service implements TriggerAction.AfterUpdate {
    public void afterUpdate(List<Account> newList , List<Account> oldList) {
        TA_Account_After_Update_Queries.getInstance().afterCaseMap = getAllCasesFromAccounts(newList);
    }

    private Map<Id, Case> getAllCasesFromAccounts(List<Account> newList) {
        Set<Id> accIds = new Set<Id>();
        for (Account myAcc : newList) {
            accIds.add(myAcc.Id);
        }
        return new Map<Id, Case>(
            [SELECT Id, Subject FROM Case WHERE AccountId IN :accIds]
        );
    }
}

} `

`public class TA_Account_AfterUpdates implements TriggerAction.AfterUpdate {

public void afterUpdate(List<Account> newList, List<Account> oldList) {
    Map<Id,Account> oldMap = new Map<Id,Account>(oldList);
    Map<Id, Case> caseIdtoAcc = TA_Account_After_Update_Queries.getInstance().afterCaseMap;
    Map<Id, Account> accountId2Case = new Map<Id,Account>(newList);

    for (Account aList : newList) {
        if ( TriggerBase.idToNumberOfTimesSeenAfterUpdate.get(aList.id) == 1 
                && aList.Name != oldMap.get(aList.id).Name
        ) {
            CaseHelper.createCaseAfterAccountRename(accountId2Case);
        }
    }
}

}`

I think this should works or maybe im wrong. I just tried to implement this pattern (which is looks amazing). Can you please check that ?

Metadata are configured and set with order 0 and using after update on account

g1b3r commented 2 years ago

my bad :)

g1b3r commented 2 years ago

i deleted by mistake a custom md and started working but after that map is empty

mitchspano commented 2 years ago

I think your issue is caused by referencing the TA_Account_After_Update_Queries class in the Trigger_Action__mdt record, instead of the inner TA_Account_After_Update_Queries.Service class.

Separating this into an inner class is necessary to support the singleton pattern because singletons can't be instantiated using the Type.forName mechanism. The top level class is the singleton and the inner Service class enables it to be used in the framework.

There are a few additional opportunities to improve here:

g1b3r commented 2 years ago

Thank you thats helps me a lot :-) So using this framework i should rather create a more classes where will be executed different logic ? :-) I already create a proper query class and this is looks amazing :)

mitchspano commented 2 years ago

Correct, we want multiple classes, each with a single responsibility or reason to change.

The best analogy I can make is this: if you were a chef, the legacy way of writing triggers is like writing all of your recipes all together on one long scroll. With the Trigger Actions Framework, you are writing your recipes on their own index cards. It makes it much easier to understand a single recipe, and to sort/organize them however you best see fit.

g1b3r commented 2 years ago

Thank you for your help :) Good job with this framework :)