【问题标题】:Update related records with an Apex trigger使用 Apex 触发器更新相关记录
【发布时间】:2021-05-04 09:09:19
【问题描述】:

我有以下用例,无法为其编写正确的触发器

在对象帐户上,我们拯救了我们的患者。每个患者都有一名联网的全科医生 (GP)。全科医生保存在对象联系人中。有时全科医生退休,新的全科医生接管了全科医生,因此与该全科医生有联系的患者必须更换为新的全科医生。

我在 Salesforce 中创建了对象联系人 2 字段、GPChange__c(布尔值)和 NewGP__c(联系人查找字段)。当用户将布尔字段设置为 true 并填写新的 GP 时,必须运行 Apex 触发器并收集连接到“退休”GP 的所有帐户(患者),并使用来自 NewGP__C 的 ID 更新帐户上的字段 GeneralPracticioner__c。

这是我走了多远,它会运行和收集,但不会更新字段。谁能帮帮我?

 trigger trgnewGP on Contact (before update) {
    for (Contact mycontact : Trigger.new) {
        if (mycontact.GPChange__c = true && mycontact.NewGP__c != null){
            list <account> gps = [SELECT GeneralPracticioner__c from account
                                    where GeneralPracticioner__c =: mycontact.id];
            for(Account acc : gps){
            if (gps.size() > 0) {
                acc.GeneralPracticioner__c = mycontact.NewGP__c;
            
                    
                    } }
            }
    }
}

【问题讨论】:

    标签: salesforce apex


    【解决方案1】:

    该代码存在一些问题:

    • if (mycontact.GPChange__c = true ... - 小心:您将 true 分配给 GPChange__c。请记住,无需编写 checkboxField == true,它已经解析为布尔值。
    • 没有 dml,它永远不会更新帐户。
    • 没有批量化:您正在循环内执行查询,因此可能会引发 LimitException(SOQL 查询过多:101)

    为了拉出查询,您需要收集退休GP的Id。
    然后您可以使用Trigger.NewMap检索需要更新的帐户记录并设置GeneralPracticioner__c

    trigger trgnewGP on Contact (before update) {
        List<Id> retiredGpIds = new List<Id>();
        for (Contact gp : Trigger.new) {
            if (gp.GPChange__c && gp.NewGP__c != null) {
                retiredGpIds.add(gp.Id);
            }
        }
        
        if (!retiredGpIds.isEmpty()) {
            List<Account> patients = [SELECT GeneralPracticioner__c from Account WHERE GeneralPracticioner__c IN :retiredGpIds];
            for (Account acc : patients) {
                acc.GeneralPracticioner__c = Trigger.NewMap.get(acc.GeneralPracticioner__c).NewGP__c;
            }
            update patients;
        }
    }
    

    由于没有更新联系人记录,我将在 after update 中运行此触发器。


    更新:

    奇怪的是,当我尝试使用 Dataloader [...] 时,它运行良好并且没有任何顶点 CPU 错误。

    Dataloader 使用批量 api,它在异步上下文中运行,因此它们具有更高的CPU Limit:60 秒 vs 10 秒。

    我建议在触发器处理程序类的future 方法中提取该触发器的逻辑。
    它应该看起来像:

    @future
    public static void updateGeneralPracticioner(List<Id> retiredGpIds) {
        Map<Id, Contact> gpMap = new Map<Id, Contact>([SELECT Id, NewGP__c FROM Contact WHERE Id IN :retiredGpIds);
        List<Account> patients = [SELECT GeneralPracticioner__c from Account WHERE GeneralPracticioner__c IN :retiredGpIds];
        for (Account acc : patients) {
            acc.GeneralPracticioner__c = gpMap.get(acc.GeneralPracticioner__c).NewGP__c;
        }
        update patients;
    }
    

    触发器:

    trigger trgnewGP on Contact (after update) {
        List<Id> retiredGpIds = new List<Id>();
        for (Contact gp : Trigger.new) {
            if (gp.GPChange__c && gp.NewGP__c != null) {
                retiredGpIds.add(gp.Id);
            }
        }
    
        if (!retiredGpIds.isEmpty()) {
            ContactTriggerHandler.updateGeneralPracticioner(retiredGpIds);
        }
    }
    

    【讨论】:

    • 不错!非常感谢您的建议和重写代码。高度赞赏。明天试试这个,如果工作正常,现在就让你看看。
    • @Reverb 是的,异步方法应该可以解决问题。我更新了答案。
    • 太棒了!谢谢重写。还不熟悉处理程序中的未来方法。经过研究,测试类的编写与“正常”测试类有点不同?
    • @Reverb 不是。如果您已经使用 Test.startTest()Test.stopTest() 一切都会好起来的。为了有有意义的断言,请务必在Test.stopTest()之后查询由异步方法更改的记录
    • 谢谢!编写了测试类,一切都在生产中完美运行。
    【解决方案2】:

    @RubenDG

    脚本完成了这项工作,非常好。但是,当更多结果 >~100 条记录时,我会得到 APEX CPU 时间限制。对象帐户上还有其他过程,但不是繁重的过程。为测试其他一些与帐户相关的 WF 规则或进程禁用,但仍会获得 CPU 限制。我认为最大更新的患者永远不会超过 1500 人......换句话说。没有全科医生有超过 1500 名患者。所以这不是很多。

    Screenshot

    奇怪的是,当我尝试使用 Dataloader 或 Workbench 并在 Account 上的 GeneralPracticioner__c 字段上进行更新(1200 条记录)时,它运行良好并且没有任何顶点 CPU 错误。

    你有什么建议。编写一个异步的处理程序类? of make trigger asyc(这可能吗?)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 2021-06-30
      • 2017-07-22
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多