Salesforce Connect:外部对象与 Apex Connector Framework 完全指南

Salesforce Connect与Apex Connector Framework完全指南:外部对象Apex限制(不支持触发器托管共享/insertAsync不适用门户/Iterable Batch数据临时存储/Server Driven Pagination)、可写外部对象(insertAsync/updateAsync/upsertAsync/deleteAsync异步DML/BackgroundOperation监控)、External CDC打包(证书不可打包/EventBus.publish测试)、Mock SOQL测试(SoqlStubProvider/createSoqlStub)、DataSource.Connection五方法(sync声明ExternalId列必须/text+url+datetime+boolean+picklist+indirectLookup+externalLookup列类型/query处理COUNT聚合/QueryUtils仅测试/search多表联合/upsertRows每行callout/deleteRows)、DataSource.Provider(认证+功能静态列表/修改Connection后需重保存Provider)、External ID(必须声明/不使用敏感数据)、OAuth令牌刷新(DataSource.OAuthTokenExpiredException/refresh_token scope)、Callout(ConnectionParams封装OAuth+Basic Auth)、分页(Server-Driven queryMoreToken/Client-Driven LIMIT+OFFSET)、queryMore(queryMoreToken+totalSize)、过滤器(columnName+columnValue+EQUALS/LESS_THAN/compound AND_+OR_+NOT_子过滤器/外部系统优先过滤)、框架限制(DML禁止/Governor Limit/动态SOQL测试/Double精度18位/String>255长文本)、GitHub Issues+GitHub+Google Drive+Google Books四个完整适配器示例。...

📅 2026/7/16 ✍️ ponybai 🏷️ apex, salesforce

Salesforce Connect 与 Apex Connector Framework

Salesforce Connect

Salesforce Connect 使 Apex 代码通过适配器访问外部对象数据。使用 Apex Connector Framework 开发自定义适配器——从外部系统检索数据并在本地合成。Salesforce 以外部对象表示数据——用户和平台可无缝与外部存储的数据交互。DataSource.Connection 类需要 Salesforce Connect 附加许可证。

外部对象

外部对象与 Apex Connector Framework

外部对象的 Apex 限制:不支持 Apex 托管共享、不支持 Apex 触发器(但 OData 4.0 外部 Change Data Capture 事件支持触发器)。Database.insertAsync() 不能在门户用户上下文中执行——使用 Database.insertImmediate()。Iterable Batch Apex 运行时外部记录存储在 Salesforce 中——作业完成后删除(无论成功与否);QueryLocator Batch 不存储外部数据。若使用 QueryLocator + OData 适配器:启用 Request Row Counts、推荐启用 Server Driven Pagination(服务器端分页防止记录重复处理或跳过)。

可写外部对象:默认只读但可设置为可写——用户和 API 可创建/更新/删除外部数据。DML 操作通过专门的异步方法执行:Database.insertAsync/updateAsync/upsertAsync/deleteAsync——返回 SaveResult 含作业标识符。使用 Database.getAsyncLocator() 获取异步定位器。BackgroundOperation 对象监控写入作业进度。

External Change Data Capture 打包与测试:可将外部 CDC 组件打包到托管包中(选择测试类 → 触发器/测试/外部数据源/外部对象被带入包)。证书不可打包——订阅者组织需有同名有效证书。测试中创建 ChangeEvent 对象,通过 EventBus.publish(event) + Test.getEventBus().deliver() 测试触发器。

Mock SOQL 测试(外部对象):使用与 Data 360 DMO 相同的 SOQL Stub 框架——扩展 System.SoqlStubProvider 重写 handleSoqlQuery(),通过 Test.createSoqlStub() 注册。支持静态/动态 SOQL 查询,包括基本查询和连接查询。

Apex Connector Framework——DataSource.Connection 类:五大核心方法:

  • sync():管理员点击 Validate and Sync 时调用——返回外部系统结构元数据。定义 DataSource.Column(text/url/datetime/boolean/picklist/indirectLookup/externalLookup)和 DataSource.Table。ExternalId 列必须声明——值来自该列
  • query(QueryContext):SOQL 查询外部对象时调用。QueryContext 始终针对单个表。使用 DataSource.QueryUtils.process() 处理过滤/排序/limit/offset——但 QueryUtils 仅用于测试(生产环境需外部系统完成过滤和排序)。处理 COUNT() 聚合查询时检查 aggregation==QueryAggregation.COUNT
  • search(SearchContext):SOSL 查询或全局搜索时调用——SearchContext 可含多个 TableSelection(支持多表联合搜索)。为每个 tableSelection 返回 DataSource.TableResult
  • upsertRows(UpsertContext):外部对象创建/更新时调用——根据 ExternalId 决定 POST(插入)或 PUT/PATCH(更新)。每行一个 callout 可能触及 callout 限制
  • deleteRows(DeleteContext):外部对象删除时调用——对每个 externalId 执行 DELETE callout

DataSource.Provider 类:

  • getAuthenticationCapabilities():声明认证类型——ANONYMOUS/OAUTH 等。始终返回静态列表(不查询数据库/不 callout/不动态逻辑——变化会导致难以排查的错误)
  • getCapabilities():声明功能——ROW_QUERY(SOQL)/SEARCH(SOSL+全局搜索)/ROW_CREATE/ROW_UPDATE/ROW_DELETE/PICKLIST/MULTI_PICKLIST。同样始终返回静态列表
  • getConnection():返回 DataSource.Connection 实例。修改并保存 Connection 类后需重新保存 Provider 类——否则自定义适配器不在 Type 字段选项中显示

关键概念:

  • External IDs:每个外部对象有 External ID 标准字段——唯一标识记录。自定义适配器必须声明 ExternalId 列并提供值。不要使用敏感数据作为 External ID(Salesforce 有时存储这些值)
  • 认证:ConnectionParams 根据 Identity Type 提供凭据——Named Principal=外部数据源定义、Per User(查询/搜索)=用户认证设置、Per User(管理连接)=外部数据源定义
  • OAuth 令牌刷新:抛出 DataSource.OAuthTokenExpiredException 时自动刷新——使用刷新令牌重建 Connection。需要认证提供程序提供刷新令牌(添加 refresh_token scope 或 access_type=offline)
  • Callout:认证参数封装在 ConnectionParams 中——OAuth(this.connectionInfo.oauthToken)/Basic Auth(username/password)。若所有 callout 使用命名凭据——外部数据源可设置 No Authentication
  • 分页:Server-Driven(外部系统控制——声明 QUERY_PAGINATION_SERVER_DRIVEN 能力——提供 queryMoreToken)+ Client-Driven(使用 LIMIT/OFFSET——声明 QUERY_TOTAL_SIZE 则返回 totalSize)
  • queryMore:默认不支持——需实现分批遍历大量结果集(默认 500 条/批)。Server-Driven:TableResult 返回 queryMoreToken 直到最终批不返回 token。Client-Driven:QUERY_TOTAL_SIZE 声明 + TableResult 设置 totalSize;或每次请求多一条记录判断是否有更多数据
  • 过滤器:QueryContext 含一个 TableSelection——SearchContext 可含多个。Filter 类含 columnName/columnValue/type(EQUALS/LESS_THAN/AND_/OR_/NOT_)。子过滤器(compound filter)在 subfilters 属性中。最佳实践:尽量在外部系统中完成所有过滤——减少返回数据量避免触及 Governor Limit

框架限制:DataSource.Connection/Provider 中不允许 DML 操作。所有 Apex Governor Limit 适用。测试方法不支持 Web Service Callout——测试外部对象使用动态 SOQL(静态 SOQL 测试外部对象失败)。Double 精度超过 18 位有效数字会丢失——使用 Decimal。String 长度超过 255 映射到长文本区域字段。

完整示例:GitHub Issues 适配器(间接查找关系/外部查找关系/Date+Picklist 字段/DML 操作)、GitHub 适配器(间接查找关系 Contact.github_username)、Google Drive 适配器(OAuth callout/测试中 mock 响应替代真实 callout)、Google Books 适配器(API 最大 40 条限制/禁用排序列)。所有适配器实现 DataSource.Connection(sync+query+search+/−upsertRows+/−deleteRows)和 DataSource.Provider(认证+功能+连接)。

Apex Connector Framework 是将任何外部数据源无缝集成到 Salesforce 中的终极工具——从 REST API 到数据库再到云存储——通过自定义适配器实现深度连接。