Salesforce学习笔记之Actions and Recommendations(续)

上次对这个Actions and Recommendations进行了初步研究,因为一些问题没有得到很好的解决,又花了很多时间,终于得到了一个比较好的解决方案。小结一下。

1. 生成Actions and Recommendations下栏目最基本的有两种方法:一是通过Deployment,优点是操作简单,另外,还可以很方便地通过点击Add按钮添加项目,缺点是无法定义这些项目显示在A&R下的条件。二是通过Process Builder。官方文档上介绍的主要是这两种方法,另外还有通过Apex或者web service来建。

2.Process Builder的主要优点是比较简单直观,另外的优点主要是因为运行在System Context下,可以不受当前用户的权限限制,而且,通过它去运行某些Flow,同样也在System Context下,不受权限限制。但是,如果通过它去运行Record triggered Flow,则不是在System Context下,因为Record triggered Flow只能运行在当前用户权限下,无法修改这一设置。

Process Builder的主要缺点是:

1)除非触发条件设置得能够保证执行一次后就不可能再触发,或者开始设置成只在建新纪录时才触发,否则因为它无法检查Flow或者QuickAction是否已经存在,会在A&R下重复建项目。

2)在Process Builder下调用Apex,无法获得返回值,相当于只能调用void类型的方法。

3)不支持before saved类型的触发。

2. 另一个方法是用Flow来建,又可分为用Record triggered Flow和Auto launched flow。前者的好处主要是有个$Record变量,不需要再用一个Get Record元素去取当前SObject的信息,另外的优点是支持before saved类型的触发条件。但是缺点一是不能运行在System Context下,某些牵涉到用户权限的需求不能实现。二是$Record变量在调试Flow时反而不方便。

前者的缺点正好是后者的优点,而优点又成了后者的缺点。

而两者共同的优点是

1)可以用图形化的形式定义触发条件,比较适合编程经验少,但熟悉业务逻辑的管理员和业务分析员

2)调用Apex,可以获得返回值。

两者共同的缺点就是某些操作比较笨拙。比如遍历时,实现如下的逻辑:

bool isFound = false;

foreach (foo in bar) {

    if (满足某个条件) {

         isFound = true;

         break;

    }

}

if (isFound == true) {//后续操作

}

如果用Flow来实现就很麻烦,无法实现上面的break操作,只能全部遍历完再来判断isFound == true。

3. 不管用哪种方法,在A&R下显示项目,本质是对RecordAction对象的操作。下面谈有关的问题。第一个问题:如何避免在A&R下生成重复项?

固然可以用Flow来实现,但很麻烦,所以考虑用Apex。因为业务逻辑放在Flow里比较好,所以打算用Apex来找出已经存在的RecordAction,然后返回Flow尚未存在,需要创建的RecordAction。然后Flow里设置触发条件,再用Creat Record元素来建RecordAction。这是最初的设计。

后来发现主要缺点是Flow里的元素比较多,线条很多,看上去有点乱。但这还不是主要问题,碰到了第二个问题:如何当一个Flow执行一遍,完成之后,避免在A&R下再次生成项目?

因为Flow完成后,只要刷新页面,对应的RecordAction就会自动删除,然后就只有在RecordActionHistory里才找得到踪迹。而RecordActionHistory是所谓的Big Object,不能在触发器里直接查询,一查就报错。虽然调试Flow的时候好好的,不出错,但一旦正式运行,马上出错。

为了解决这个问题,先是发现QuickAction执行后,对应的RecordAction不会删除,就考虑用QuickAction来包装Flow。但发现QuickAction缺省是在一个模态框里显示,而Flow缺省应该是在一个Tab里显示,结果被QuickAction包装后,也执行在模态框里,界面很难看。只好又做了个Lightning  Component,用它打开另外一个Lightning Component,并显示在Tab里,在第二个Lightning Component里再去运行Flow。然后把第一个Lightning  Component加到QuickAction里,就基本做好了。显然,一层套一层,很麻烦。而且很快发现一个问题。就是QuickAction的RecordAction不会显示Complete状态(所以它不会被删掉),但这样一来,也无从得知Flow到底有没有运行完。

做了半天白做了,还好柳暗花明又一村,终于又找到一个办法,就是用future方法也即异步模式去查RecordActionHistory。

同时,修改了设计,用apex实现查找已存在的RecordAction和已经执行完毕的Flow类型的RecordAction(QuickAction类型的还是没法查),然后直接用apex创建RecordAction。这样一来,查找,创建的功能全移到apex,Flow那头只剩下定义触发条件和给apex提供输入参数的几个元素,顿时清爽了许多。

从Flow调用apex(用Process Builder也一样),需要在apex类里定义一个带@invocableMethod属性的方法,而且一个类里只能有一个方法带此属性。另外,只允许一个输入参数。如果输入参数是List<foo>,表面看来是个List,实际上只能传入一个对象,如果需要传入多个对象,有个技巧,就是把输入参数定义为List<List<foo>>,再套上一个List,就能传入多个值了。

还有前面已经提到,Flow里的PickList域,传到apex后,需要用String.valueOf()才能取值,否则报cast错误。这是Salesforce的bug。

另外,在带@invocableMethod属性的方法里可以调用带@future属性的方法,也是诸多限制。首先不允许传对象类型的参数,只能传List<String>或者多个String或其他原始类型的参数,其次@future方法只能是void类型,没有返回值,而且不能设置回调函数!,也不能在@future方法里,再去调用别的@future方法。所以没办法,只能把对象平展成字符串,传进去之后再拼装成对象。不管怎么样,好歹终于解决了第二个问题:当一个Flow执行一遍,完成之后,避免在A&R下再次生成项目。缺点主要是一是QuickAction类型的RecordAction仍然没有办法,只能通过修改QuickAction后面的Flow,在执行完毕时修改SObject里自定义的IsFlowRun域来判断Flow是否运行过了。二是用@future方法,反应稍有些慢(因为是异步,无法保证何时响应)。不过异步的Governor Limit比同步方式大很多,这方面的顾虑可以少些。而且结合Deployment,用户可以手工在A&R下添加。这样总算比较满意地解决了这个问题。

意犹未尽,又添加了一些功能,比如允许用户指定不需要查RecordActionHistory,甚至可以允许重复项。还允许当Flow的触发条件不满足时,删除对应的RecordAction。因为@invocableMethod只能传一个参数,Flow里又难以使用自定义对象,所以只好在RecordAction的Status域上做文章,自己定义Unlinked表示删除,Paused表示不需要查RecordActionHistory,Started表示允许重复项。缺省的New则表示不允许重复项,也必须查RecordActionHistory。这样,功能又增强了。

补充:

开始时把所有查RecordAction和RecortActionHistory的操作全部放在@future方法里,但在调试时发现无法删除记录,插记录时也有问题,移出来就好了。看来这个@future方法很tricky,尽量避免。最后修改为只有查RecortActionHistory的功能放在@future方法里,同时添加代码,在@future方法里再查一次RecordAction,因为@future方法执行时,说不定对象有变化,再查一次比较保险。

另外将来如要再拓展功能,也许可加一个用户自定义对象,这样在Flow里设参数就方便了,不用再利用RecordAction的Status域。现在先对付着用。

在折腾A&R的过程中,接触了一些相关技术,使用了一些相关工具,得到不少副产品,算是有所收获。

posted @ 2020-08-08 12:26  平静寄居者  阅读(226)  评论(0编辑  收藏  举报