Salesforce触发器无限循环



首先,我们有一个通过api将数据同步到salesforce和从salesforc同步数据的产品。当记录在我们的平台中更新时,数据会被推送到salesforce,当数据在salesforch中更新时会被推送给我们的产品。我们遇到的问题是一个相当麻烦的无限循环。SalesForce中是否有一种方法可以确定谁在执行触发器,以便在我们的产品中更新数据并将其推送给SalesForce时,触发器不会触发?我以前没有看到关于这个的执行信息,所以我真的不确定

谢谢!

我认为除了Trigger.isExecuting之外没有其他东西,它只是简单地"告诉"您是否已经处于触发器上下文中,或者您是否来自Visualforce、API或匿名执行。

一种可能的解决方案是创建一个自定义字段,保留最新更新的来源。然后,这可以用于在触发器内正确路由逻辑,并避免在上次更新来自外部系统时调用。此外,您还可以循环浏览Trigger.old和Trigger.new中的所有字段,以查看哪些字段发生了更改。这样,当您的记录(SystemTimeStamp、LastModifiedDate等)上没有任何有趣的实际更改时,您可以避免与外部系统进行进一步不必要的同步。以下是如何做到这一点的示例:

trigger ContactDescribeExample on Contact (before update) 
{
      // Get describe fields to evaluate old and new triggers with
      Map<String, Schema.SObjectField> fldObjMap = Schema.SObjectType.Contact.fields.getMap();
      List<Schema.SObjectField> fldObjMapValues = fldObjMap.values();
      // Flag to determine if field(s) other than FirstName caused this change (FirstName is just an example)
      Boolean hasOtherChange = false;
      // Loop through trigger batch
      for(Contact c : Trigger.new)
      {
            for(Schema.SObjectField s : fldObjMapValues)
            {
                  String fldName = s.getDescribe().getName();
                  // Filter out fields we're not interested in
                  if(fldName != 'FirstName' && fldName != 'LastModifiedDate' && fldName != 'LastModifiedById' && fldName != 'SystemModstamp')
                  {
                        // Check to see if old and new are different
                        if(c.get(fldName) != Trigger.oldMap.get(c.Id).get(fldName))
                              hasOtherChange = true;
                  }
            }
      }
}

对于任何在谷歌上发现这一点的人,我通过添加一个类来解决一个非常类似的问题,该类设置了一个公共静态变量,然后触发器会检查该变量。默认情况下为false,如果设置为true,则触发器不会运行。以下示例:

public class Recursive {
  // Static variables to avoid recursion on trigger operation
  private static boolean working = false;
  public static boolean isWorking() {
      return working;
  }
  // Set variable to true to mark record as working
  public static void setWorking() {
      working = true;
  }
  public static void setClosed() {
      working = false;
  }
}

然后触发器被封装在以下内容中:

if (!Recursive.isWorking()) {
  // trigger code here
}

作为一个静态变量,它在整个代码执行过程中都保持设置,所以我的apex设置的第一件事是Recursive.setWorking();,以防止触发器在其余方法中触发。

我同意Adam关于如何更好地确定何时执行同步的观点。您还可以考虑使用UserInfo.getUserId()方法查看当前正在更新记录的用户,然后查找该用户。

我想,为了使集成工作,您必须为外部产品分配一个用户。希望这是他们独有的账户,这将是最好的做法。如果是这样,那么你可以看看当前用户是谁,如果是外部产品,你可以忽略发送另一个更新的尝试。

对于要筛选出逻辑的每个"豁免源",您可以在Number(18,0)类型的目标对象上创建一个字段。我通常将此字段称为"[Job]上次更新"。该字段不应出现在任何面向用户的页面布局上。

然后,每当您的豁免源执行更新时,您都会将该字段设置为System.currentTimeMillis()。您的触发器会检查该字段是否已更改,如果已更改,则豁免您希望为该源省略的逻辑。

Adam提到的解决方案——保留最新更新的来源——也可以,但我发现,如果你不总是正确更新或检查它是否发生了变化,它可能会出错。这就是为什么我更喜欢在您想要逻辑豁免时更改的字段,并且您只需要为那些豁免的更改源更新它。

如果您使用专用用户来处理来自您的产品的API调用,则可以禁用这些调用的"发送出站消息用户权限"。这不会阻止一些触发代码的运行,但会阻止每次开发的任何更新周期。

最新更新