精通 Salesforce Connect:架构师无缝数据集成指南
背景与应用场景
作为一名 Salesforce 架构师,我日常工作中面临的核心挑战之一就是如何优雅地处理数据孤岛(Data Silos)。企业的数据通常散布在各个系统中:ERP 系统中的订单和发票,供应链系统中的库存信息,或者某个自建的旧系统中的客户历史数据。传统的数据集成方式,如 ETL(Extract, Transform, Load),通过定期同步将数据复制到 Salesforce 中。然而,这种方式存在数据延迟、存储成本增加以及维护复杂等问题。
在这样的背景下,Salesforce Connect 提供了一种截然不同的解决方案:数据虚拟化(Data Virtualization)。它允许您在 Salesforce 界面中直接查看、搜索和修改存储在外部系统中的数据,而无需将这些数据实际复制到 Salesforce。这些外部数据以一种名为外部对象(External Objects)的形式存在,对于终端用户而言,其体验与操作标准的 Salesforce 对象(如 Account 或 Contact)几乎无异。
Salesforce Connect 的应用场景非常广泛,对于架构设计具有重要意义:
- 实时订单可见性:销售团队在客户(Account)页面上,可以直接查看来自 SAP 或 Oracle ERP 系统的实时订单历史和状态。无需切换系统,也无需等待夜间的 ETL 同步。 - 统一的产品与库存视图:在创建机会(Opportunity)或报价(Quote)时,能够实时查询外部产品生命周期管理(PLM)或库存系统,获取最新的产品信息和可用库存,避免超卖。 - 敏感数据合规:对于某些受严格法规监管的行业(如金融、医疗),敏感数据可能不允许存储在云端 CRM 中。通过 Salesforce Connect,可以在 Salesforce 中引用这些数据(例如显示部分客户的财务摘要),而数据本身仍然安全地存放在企业内部的防火墙之后。 - 简化集成复杂度:当您只需要对外部数据进行“读”或“轻量级写”操作时,Salesforce Connect 提供了一种比编写复杂的双向同步 Apex/API 代码更快捷、更低成本的集成方案。
从架构师的角度来看,Salesforce Connect 是集成工具箱中一件强大的武器,它改变了我们对于“集成”的传统认知,从“移动数据”转向了“连接数据”。
原理说明
Salesforce Connect 的核心是外部数据源(External Data Sources)和外部对象(External Objects)。整个工作流程可以分解为以下几个关键部分:
1. 外部数据源 (External Data Sources)
这是连接的起点。在 Salesforce 的“设置”中,您需要创建一个外部数据源来定义如何连接到外部系统。Salesforce Connect 提供了多种适配器(Adapters)来支持不同的连接协议:
- OData 2.0/4.0 Adapter: 这是最常用也是官方推荐的方式。OData (Open Data Protocol, 开放数据协议) 是一种基于 HTTP 和 RESTful 原则的 Web 协议,用于查询和操作数据。如果您的外部系统(如 SAP, SharePoint, 或者自定义服务)能够暴露 OData 端点,集成过程将变得非常简单和标准化。
- Salesforce Adapter: 这种适配器用于实现 Salesforce 组织(Org)之间的连接。您可以将一个 Org 中的数据以外部对象的形式呈现在另一个 Org 中,非常适用于多组织架构的企业。
- Custom Adapter (Apex Connector Framework): 当外部系统不提供 OData 接口,而是提供其他形式的 API(如专有的 REST/SOAP API)时,您可以通过编写 Apex 代码来创建自定义适配器。这为连接任何系统提供了无与伦比的灵活性,也是架构师需要重点关注的部分。
2. 外部对象 (External Objects)
在配置好外部数据源后,您可以点击“验证和同步(Validate and Sync)”按钮。Salesforce 会连接到外部数据源,并读取其数据结构(例如,OData 服务中的实体)。您可以选择将哪些外部数据表或实体同步为 Salesforce 中的外部对象。同步后,Salesforce 会自动创建对应的外部对象和字段,这些字段的类型与外部系统的数据类型相匹配。
外部对象的 API 名称以 `__x` 后缀结尾(例如 `Order__x`),以此区别于自定义对象的 `__c` 后缀。尽管它们在界面上看起来很像普通对象,但它们的数据请求在底层会被 Salesforce 平台实时地转换为对外部系统的 API 调用(例如,一个 OData 查询)。
3. 数据交互流程
当用户在 Salesforce 中执行一个涉及外部对象的操作时(如查看列表、打开记录、运行报表),流程如下:
- Salesforce 平台截获该请求。
- 它识别出这是一个针对外部对象的操作。
- 通过外部数据源的配置,将用户的操作(如 SOQL 查询)转换为对应外部系统的查询语言(如 OData URL 查询参数)。
- 通过 HTTP Callout 将请求发送到外部系统的端点。
- 外部系统处理请求并返回数据(通常是 JSON 或 XML 格式)。
- Salesforce Connect 适配器解析返回的数据,并将其呈现为 Salesforce UI 中的记录和字段。
这个过程是实时发生的,确保了用户看到的数据永远是最新的。对于自定义适配器,上述第 3 步和第 6 步的转换和解析逻辑则是由您编写的 Apex 代码来完成的。
示例代码
当标准 OData 适配器无法满足需求时,我们需要使用 Apex Connector Framework 创建自定义适配器。这通常涉及实现 `DataSource.Provider` 和 `DataSource.Connection` 这两个 Apex 类。以下是一个来自 Salesforce 官方文档的简化示例,展示了如何连接到一个虚构的数据源。
1. Provider 类
Provider 类用于声明连接器的能力并建立连接。
// MyCustomDataSourceProvider.cls // 这个 Provider 类是自定义适配器的入口点。 // 它声明了适配器支持哪些能力(如查询、分页),并负责创建连接实例。 global class MyCustomDataSourceProvider extends DataSource.Provider { // 声明适配器支持的能力。 // 这里我们声明了基本查询 (ROW_QUERY) 和分页 (PAGINATION) 的能力。 override global List<DataSource.Capability> getCapabilities() { List<DataSource.Capability> capabilities = new List<DataSource.Capability>(); capabilities.add(DataSource.Capability.ROW_QUERY); capabilities.add(DataSource.Capability.PAGINATION); return capabilities; } // 当 Salesforce 需要与外部系统通信时,会调用此方法来获取一个连接实例。 // 'connectionDetails' 参数包含了在外部数据源设置中配置的所有信息。 override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionDetails) { return new MyCustomDataSourceConnection(connectionDetails); } }
2. Connection 类
Connection 类是实际处理数据请求的地方。它包含了同步(sync)、查询(query)、更新(upsert)和删除(delete)等方法的具体实现。
// MyCustomDataSourceConnection.cls // 这个 Connection 类实现了与外部系统数据交互的核心逻辑。 global class MyCustomDataSourceConnection extends DataSource.Connection { private DataSource.ConnectionParams connectionInfo; // 构造函数,保存外部数据源的配置信息。 global MyCustomDataSourceConnection(DataSource.ConnectionParams connectionDetails) { this.connectionInfo = connectionDetails; } // sync() 方法用于发现外部系统的数据结构(表和列), // 并将其转换为 Salesforce 的外部对象和字段。 // 当管理员点击“验证和同步”时,此方法被调用。 override global DataSource.TableResult sync() { // 示例:创建一个名为 "SampleTable" 的表(外部对象) List<DataSource.Table> tables = new List<DataSource.Table>(); List<DataSource.Column> columns = new List<DataSource.Column>(); // 定义外部对象的列(字段) columns.add(DataSource.Column.text('ID', 255)); // 外部 ID columns.add(DataSource.Column.text('Name', 80)); columns.add(DataSource.Column.url('Website')); columns.add(DataSource.Column.text('Description', 255)); // 'DisplayUrl' 是一个特殊列,用于定义记录的链接地址。 // 'ExternalId' 标识了哪个列是外部唯一标识符。 tables.add(DataSource.Table.builder() .name('SampleTable') .label('Sample Table') .description('A sample table from the custom data source.') .columns(columns) .primaryDisplayColumn('Name') .externalIdColumn('ID') .build()); return DataSource.TableResult.success(tables); } // query() 方法是核心,当用户查询外部对象数据时被调用。 // 'queryContext' 包含了 SOQL 查询的详细信息(如 WHERE 子句、LIMIT、OFFSET)。 override global DataSource.TableResult query(DataSource.QueryContext queryContext) { // 在真实场景中,这里会发起一个 HTTP Callout 到外部 API。 // 然后解析返回的 JSON/XML,并将其构造成 Salesforce 需要的数据行。 // 示例:构建一些静态的模拟数据 List<Map<String, Object>> sampleData = new List<Map<String, Object>>(); Map<String, Object> row1 = new Map<String, Object>(); row1.put('ID', '101'); row1.put('Name', 'Sample Record One'); row1.put('Website', 'http://www.salesforce.com'); row1.put('Description', 'This is the first sample record.'); sampleData.add(row1); Map<String, Object> row2 = new Map<String, Object>(); row2.put('ID', '102'); row2.put('Name', 'Sample Record Two'); row2.put('Website', 'http://developer.salesforce.com'); row2.put('Description', 'This is the second sample record.'); sampleData.add(row2); // 使用 DataSource.TableResult.success() 将数据返回给 Salesforce 平台。 // queryContext.tableSelection.columns 告诉我们用户查询了哪些字段。 return DataSource.TableResult.success(queryContext, sampleData); } }
注意事项
作为架构师,在设计 Salesforce Connect 解决方案时,必须充分考虑其限制和影响,这决定了方案的成败。
权限与安全 (Permissions & Security)
Named Credentials (命名凭据) 是管理外部系统认证信息的最佳实践。它将端点 URL 和认证信息(如用户名密码、OAuth 2.0 令牌)从代码或配置中分离出来,便于管理和维护,同时提高了安全性。外部对象的访问权限通过 Profile(简档)和 Permission Set(权限集)进行控制,与标准对象类似,您可以精细地控制谁可以查看、编辑或删除外部数据。
API 限制与性能 (API Limits & Performance)
这是最关键的考量点。每一次对外部对象的数据访问都会触发一次 Salesforce Callout。
- Callout 限制:这些 Callout 会计入 Salesforce 的总体 Callout 限制。对于 OData 适配器,有每小时每个用户的特定限制。对于 Apex 自定义适配器,则遵循 Apex 的 Callout 限制。高频访问的场景可能会迅速耗尽这些限制。
- 性能与延迟:数据查询的响应时间完全依赖于外部系统的性能和网络延迟。一个缓慢的外部 API 会直接导致 Salesforce 页面加载缓慢,用户体验极差。因此,必须确保外部系统能够提供低延迟、高可用的服务。
- SOQL 查询限制:对外部对象的 SOQL 查询功能受限。例如,不支持聚合函数(如 `COUNT()`, `SUM()`),不支持复杂的 `GROUP BY` 或 `HAVING` 子句。这使得外部对象不适用于需要复杂报表和仪表板的场景。
数据模型与功能限制 (Data Model & Feature Limitations)
外部对象并非万能,它们不支持 Salesforce 平台的全部功能:
- 自动化:您不能在外部对象上直接创建触发器(Triggers)、流(Flows)、工作流规则(Workflow Rules)或验证规则(Validation Rules)。 - 关系:外部对象不能位于主从关系(Master-Detail Relationship)的“从”端。但它们可以支持查找关系(Lookup Relationships),包括从标准/自定义对象查找到外部对象,反之亦然,以及在同一数据源的外部对象之间建立查找。 - 其他功能:不支持记录类型(Record Types)、公式字段中的跨对象引用限制较多,并且在搜索方面的行为也与标准对象有所不同。
错误处理 (Error Handling)
由于依赖外部系统,健壮的错误处理机制至关重要。如果外部系统宕机或返回错误,Salesforce 界面会直接向用户显示错误信息。在使用 Apex 自定义适配器时,您必须在代码中实现完善的 `try-catch` 逻辑,处理网络超时、认证失败、无效数据等各种异常情况,并向用户提供有意义的反馈。
总结与最佳实践
Salesforce Connect 是一个强大的数据虚拟化工具,它为集成外部数据提供了轻量级、实时的解决方案。作为架构师,我们需要清晰地认识到它的定位和权衡。
最佳实践总结:
- 明确使用场景:当数据量巨大、变化频繁、或因合规性要求不能存储在 Salesforce 中时,优先考虑 Salesforce Connect。它最适合“查看和偶尔修改”的场景。
- 避免用于复杂业务逻辑:如果需要在数据上运行复杂的 Salesforce 自动化(如触发器、流)或进行聚合分析报表,传统的 ETL 或 API 集成方式(将数据复制到 Salesforce 自定义对象)可能是更好的选择。
- 性能优先:在方案设计阶段,务必对外部数据源进行性能压力测试。鼓励外部系统提供方实现服务器端分页和过滤(OData 协议原生支持),以减少数据传输量,提升性能。
- 安全第一:始终使用命名凭据(Named Credentials)来处理认证,切勿在代码或配置中硬编码任何敏感信息。
- 理解限制:在向业务方承诺功能之前,请确保您和您的团队都完全理解外部对象的功能限制。管理好业务方的期望是项目成功的关键。
- 选择合适的适配器:尽可能使用标准的 OData 适配器,因为它们经过优化且易于维护。仅在连接非 OData 源时,才投入资源开发 Apex 自定义适配器。
总而言之,Salesforce Connect 不是要取代所有传统的集成模式,而是为我们的集成架构提供了另一种选择。通过明智地运用它,我们可以构建出更灵活、高效且成本更低的解决方案,真正实现 360 度的客户视图。
评论
发表评论