Salesforce Connect:无缝集成外部数据的实时桥梁

身份:Salesforce 咨询顾问


背景与应用场景

在当今的企业数字化转型浪潮中,数据已经成为驱动业务决策的核心资产。然而,一个普遍存在的挑战是数据孤岛(Data Silos)问题。企业的关键数据往往分散在不同的系统中,例如:客户的订单历史存储在企业资源规划(ERP)系统中,产品库存信息在供应链管理(SCM)系统中,而客户关系管理则由 Salesforce 负责。当销售人员在 Salesforce 中查看客户信息时,如果无法实时获取其在 ERP 系统中的订单和支付状态,就很难提供全面、及时的客户服务。

传统的解决方案通常是采用 ETL(Extract, Transform, Load)工具,定期将外部数据抽取、转换并加载到 Salesforce 中。这种方式虽然可行,但存在几个明显的缺点:

  • 数据延迟:数据不是实时的,可能导致业务决策基于过时的信息。
  • 存储成本:将大量外部数据复制到 Salesforce 会消耗宝贵的数据存储空间,增加运营成本。
  • 维护复杂性:需要维护复杂的同步逻辑、监控任务和错误处理机制,增加了 IT 部门的负担。

为了解决这些痛点,Salesforce 推出了 Salesforce Connect,它是一种强大的数据集成服务。Salesforce Connect 遵循数据虚拟化(Data Virtualization)的理念,允许您在 Salesforce 中直接查看、搜索和修改存储在外部系统中的数据,而无需将这些数据实际复制到 Salesforce 中。这些外部数据在 Salesforce 中以 External Objects (外部对象) 的形式呈现,对于用户来说,其使用体验与标准的 Salesforce 自定义对象几乎没有区别。

以下是一些典型的应用场景:

  • 360度客户视图:在客户(Account)页面上,直接展示来自 ERP 系统的历史订单、发货状态和发票信息。
  • 实时库存查询:销售人员在创建报价(Quote)或机会(Opportunity)时,能够实时查询外部库存系统,确保产品可用性。
  • 金融数据整合:在金融服务云(Financial Services Cloud)中,将客户的银行账户、交易记录等核心银行系统数据作为外部对象进行展示。
  • 法规遵从:对于某些有严格数据驻留(Data Residency)要求的行业(如医疗、政府),可以将敏感数据保留在本地或指定的系统中,同时通过 Salesforce Connect 在 Salesforce UI 中进行安全的访问和操作。

作为一名 Salesforce 咨询顾问,我经常向客户推荐 Salesforce Connect,因为它提供了一种轻量级、低成本且实时的数据集成方案,能够快速打破数据壁垒,提升用户体验和业务效率。

原理说明

Salesforce Connect 的核心原理是“按需访问,而非复制存储”。当用户在 Salesforce 中执行访问外部对象的操作时(例如,打开记录、查看列表视图、运行报表),Salesforce 会在后台实时向外部数据源发起一个 API 调用(Callout)。外部系统接收到请求后,处理并返回相应的数据,Salesforce 再将这些数据呈现给用户。整个过程对用户是透明的。

实现这一机制的关键在于两个核心组件:External Data Sources (外部数据源)External Objects (外部对象)

1. 外部数据源 (External Data Sources)

外部数据源是 Salesforce 与外部系统之间的连接配置。它定义了如何连接到外部系统、使用何种协议进行通信以及采用哪种身份验证方式。Salesforce Connect 支持多种适配器(Adapters)来连接不同类型的外部系统:

  • OData 2.0/4.0 Adapter:OData (Open Data Protocol) 是一种基于 RESTful API 的开放标准,用于构建和消费可查询、可操作的 Web 服务。如果您的外部系统(如 SAP、SharePoint)提供了 OData 端点(Endpoint),这是最常用、最简单的连接方式。
  • Cross-Org Adapter:用于连接另一个 Salesforce org。您可以将一个 org 中的数据作为外部对象实时展示在另一个 org 中,非常适合公司内部多 org 架构的场景。
  • Custom Adapter (Apex Connector Framework):如果您的外部系统不提供 OData 接口,但有自己的 REST 或 SOAP API,您可以使用 Apex Connector Framework 编写自定义的 Apex 代码来“翻译”Salesforce 的请求,并处理外部系统的响应。这提供了极高的灵活性,可以连接到几乎任何类型的外部数据源。

2. 外部对象 (External Objects)

在配置好外部数据源后,您可以“同步”该数据源。Salesforce 会查询外部系统的元数据(例如,OData 服务中的实体),并允许您选择要创建为外部对象的表或实体。创建后,外部对象就出现在 Salesforce 的设置菜单中,拥有自己的 API 名称(以 `__x` 结尾)。

您可以像操作自定义对象一样对外部对象进行配置:

  • 设置字段级别的安全性和简档权限。
  • 创建自定义选项卡和页面布局。
  • 与其他 Salesforce 对象(标准或自定义)建立关系(查找关系、间接查找关系、外部查找关系)。
  • 在 SOQL 查询、Salesforce 全局搜索、报表和仪表板中使用它们(存在一些限制)。

当用户与外部对象交互时,Salesforce Connect 会将用户的操作转换为相应的协议请求。例如,一个 SOQL 查询会被转换为一个 OData 查询(包含 `$filter`、`$select` 等参数),然后发送到外部数据源的 URL 端点。

示例代码

虽然 Salesforce Connect 的 OData 适配器大部分是声明式配置,但当我们面对没有标准 OData 接口的专有系统时,Apex Connector Framework 就显得至关重要。作为咨询顾问,为客户设计和实现这种自定义连接器是高级集成的常见需求。以下代码示例展示了如何创建一个简单的自定义适配器,它连接到一个虚构的外部数据服务。

此示例包含两个关键的 Apex 类:`DataSource.Provider` 和 `DataSource.Connection`。Provider 类负责声明连接器的能力和获取连接实例,而 Connection 类则负责处理实际的数据操作,如同步、查询和身份验证。

注意:以下代码严格遵循 Salesforce 官方文档中的 `DataSource` 命名空间和类结构。

创建自定义连接器 Provider 类

/**
 * MyCustomDataSourceProvider.cls
 *
 * Provider 类用于定义自定义连接器的元数据和功能。
 * 它告诉 Salesforce 这个连接器支持哪些认证方式,以及需要哪些功能。
 */
public class MyCustomDataSourceProvider extends DataSource.Provider {

    /**
     * getAuthenticationCapabilities() 方法
     * 返回此连接器支持的认证类型列表。
     * 这里我们声明它支持“基本认证”(用户名/密码)。
     * @return 返回认证能力列表。
     */
    public override List<DataSource.AuthenticationCapability> getAuthenticationCapabilities() {
        List<DataSource.AuthenticationCapability> capabilities = new List<DataSource.AuthenticationCapability>();
        capabilities.add(DataSource.AuthenticationCapability.BASIC); // 支持基本认证
        return capabilities;
    }

    /**
     * getCapabilities() 方法
     * 返回此连接器支持的操作类型。
     * 例如,ROW_QUERY 表示支持行查询,SEARCH 表示支持搜索。
     * @return 返回连接器能力列表。
     */
    public override List<DataSource.Capability> getCapabilities() {
        List<DataSource.Capability> capabilities = new List<DataSource.Capability>();
        capabilities.add(DataSource.Capability.ROW_QUERY); // 支持基于行的查询
        capabilities.add(DataSource.Capability.SEARCH);    // 支持搜索功能
        return capabilities;
    }

    /**
     * getConnection() 方法
     * Salesforce 在需要与外部系统交互时会调用此方法。
     * 它返回一个 DataSource.Connection 类的实例,该实例将处理实际的数据请求。
     * @param connectionInfo 包含外部数据源配置信息的上下文。
     * @return 返回 DataSource.Connection 的一个实例。
     */
    public override DataSource.Connection getConnection(DataSource.ConnectionParams connectionInfo) {
        return new MyCustomDataSourceConnection(connectionInfo);
    }
}

创建自定义连接器 Connection 类

/**
 * MyCustomDataSourceConnection.cls
 *
 * Connection 类是自定义连接器的核心,负责处理所有与外部系统的通信。
 * 它实现了同步(sync)、查询(query)和搜索(search)等核心逻辑。
 */
public class MyCustomDataSourceConnection extends DataSource.Connection {

    private DataSource.ConnectionParams connectionInfo;

    /**
     * 构造函数
     * @param connectionInfo 包含外部数据源配置,如端点URL、凭据等。
     */
    public MyCustomDataSourceConnection(DataSource.ConnectionParams connectionInfo) {
        this.connectionInfo = connectionInfo;
    }

    /**
     * sync() 方法
     * 当管理员在 Salesforce 设置中点击“验证和同步”时调用此方法。
     * 它应该连接到外部系统,获取其数据结构(表和列),
     * 并将其转换为 Salesforce 能理解的 DataSource.Table 和 DataSource.Column 对象。
     * @return 返回可用于创建外部对象的表列表。
     */
    public override List<DataSource.Table> sync() {
        // 在实际项目中,这里会发起一个 HTTP Callout 到外部系统的元数据端点
        // 以下为硬编码的示例,模拟从外部系统获取到的表结构
        List<DataSource.Table> tables = new List<DataSource.Table>();
        
        // 定义“订单”表的列
        List<DataSource.Column> columns = new List<DataSource.Column>();
        columns.add(DataSource.Column.text('OrderID', 255)); // 订单ID,文本类型
        columns.add(DataSource.Column.text('CustomerName', 255)); // 客户名称
        columns.add(DataSource.Column.url('DisplayUrl')); // Salesforce 要求的标准外部对象字段
        columns.add(DataSource.Column.text('ExternalId')); // 外部ID,用于唯一标识记录
        
        // 创建“订单”表
        String tableName = 'Orders';
        String tableLabel = 'Orders';
        tables.add(DataSource.Table.get(tableName, tableLabel, null, columns));
        
        return tables;
    }

    /**
     * query() 方法
     * 当用户查询外部对象时(如打开列表视图或运行报表),此方法被调用。
     * 它接收一个 DataSource.QueryContext 对象,其中包含查询的详细信息
     * (如要查询的表、列、过滤条件、排序规则等)。
     * @param context 查询上下文。
     * @return 返回查询结果。
     */
    public override DataSource.TableResult query(DataSource.QueryContext context) {
        // 在实际项目中,这里会构建一个 HTTP 请求(例如 REST GET 请求),
        // 将 context 中的过滤条件转换为外部系统API的查询参数。
        // 然后解析返回的 JSON/XML,并将其映射到 DataSource.Row 对象中。
        
        // 以下为硬编码的示例,模拟返回的查询结果
        List<Map<String, Object>> data = new List<Map<String, Object>>();
        
        Map<String, Object> row1 = new Map<String, Object>();
        row1.put('OrderID', 'ORD-001');
        row1.put('CustomerName', 'Global Tech Inc.');
        row1.put('ExternalId', 'ext-001');
        row1.put('DisplayUrl', '/services/apexrest/myorg/orders/ext-001');
        data.add(row1);
        
        Map<String, Object> row2 = new Map<String, Object>();
        row2.put('OrderID', 'ORD-002');
        row2.put('CustomerName', 'United Solutions');
        row2.put('ExternalId', 'ext-002');
        row2.put('DisplayUrl', '/services/apexrest/myorg/orders/ext-002');
        data.add(row2);
        
        return DataSource.TableResult.get(context, data);
    }
    
    /**
     * search() 方法
     * 当用户使用全局搜索时,此方法被调用。
     * 逻辑与 query() 类似,但通常是为更广泛的文本搜索而优化。
     * @param context 搜索上下文。
     * @return 返回搜索结果列表。
     */
    public override List<DataSource.TableResult> search(DataSource.SearchContext context) {
        // 实现搜索逻辑,类似于 query()
        // 实际项目中,这会调用外部系统的搜索API
        return new List<DataSource.TableResult>();
    }
}

注意事项

在规划和实施 Salesforce Connect 项目时,必须充分考虑其限制和潜在影响,以确保方案的可行性和稳定性。

  • API 调用限制:每次对外部对象的操作(查看记录、刷新列表、执行查询)都会消耗一个 Salesforce API Callout。请密切关注您的 org 的每日 Callout 限制。高频访问的外部对象可能会迅速耗尽这些限制,影响其他集成。
  • 性能和延迟:由于数据是实时查询的,性能直接取决于外部数据源的响应速度和网络延迟。一个响应缓慢的外部系统会导致 Salesforce 页面加载缓慢,用户体验差。在实施前,必须对外部系统的 API 进行充分的性能测试。
  • 外部对象功能限制:外部对象并不支持标准或自定义对象的所有功能。例如:
    • 不支持 Apex Triggers、验证规则和工作流规则(部分功能可通过 Flow 实现)。
    • 不支持将外部对象作为父项的主从关系。
    • 在公式字段、报表和 SOQL 查询中的使用受到限制。例如,聚合查询(`COUNT()`、`SUM()`)的支持有限,并且外部对象不能是某些复杂报表类型的主对象。
    • 记录所有权和共享模型与 Salesforce 标准对象不同,其访问权限主要由外部数据源的配置决定。
  • 数据可写性:Salesforce Connect 是否支持对外部数据进行创建、编辑和删除操作,完全取决于外部数据源的设置。如果 OData 端点或自定义适配器实现了写操作,您可以在 Salesforce 中启用这些功能。否则,外部对象将是只读的。
  • 身份验证:需要仔细规划身份验证策略。是使用一个共享的系统账户(Named Principal)连接外部系统,还是让每个用户使用自己的凭据(Per User)?这涉及到安全性和数据可见性的重要决策。
  • - 错误处理:必须设计健全的错误处理机制。如果外部系统宕机或返回错误,Salesforce 界面应能优雅地处理这些异常,并向用户提供清晰的提示。

总结与最佳实践

Salesforce Connect 是一个强大的数据集成工具,它通过数据虚拟化的方式,提供了一种“零拷贝”、实时的外部数据访问方案。它特别适用于那些数据量大、更新频繁,或者因合规性要求不能存储在 Salesforce 中的场景。

作为一名 Salesforce 咨询顾问,我为客户提供以下最佳实践建议:

  1. 明确业务需求,选择正确的工具:在选择 Salesforce Connect 之前,要先问一个关键问题:“我需要对这些数据在 Salesforce 中做什么?”如果只是查看和简单更新,Connect 是绝佳选择。如果需要复杂的自动化逻辑(如 Apex Triggers)、精细的共享模型或高性能的聚合报告,那么传统的 ETL 数据同步方案可能更合适。
  2. 优先使用标准适配器:如果外部系统支持 OData,请优先使用 OData 2.0 或 OData 4.0 适配器。这能最大限度地减少开发和维护成本。只有在无法使用标准适配器时,才考虑投入资源开发自定义的 Apex 连接器。
  3. 设计以性能为先:在设计页面布局和列表视图时,尽量减少默认加载的外部对象字段数量,避免一次性触发过多的数据请求。使用分页(Server-driven Paging)来处理大型数据集,而不是一次性加载所有记录。
  4. 理解并监控限制:在项目上线前,评估预期的使用量是否会超出 API Callout 限制。上线后,使用 Salesforce 的事件监控(Event Monitoring)或相关工具持续跟踪 Callout 的使用情况,以便及时优化。
  5. 建立清晰的治理模型:明确外部数据的所有权和维护责任。确保外部系统的 API 变更能够及时通知 Salesforce 团队,避免因外部接口变动导致集成中断。

总而言之,Salesforce Connect 并非万能的数据集成解决方案,但它在正确的场景下能够发挥巨大价值,帮助企业快速、高效地构建统一的客户视图,打破信息孤岛,从而做出更明智的业务决策。

评论

此博客中的热门博文

Salesforce 登录取证:深入解析用户访问监控与安全

Salesforce Experience Cloud 技术深度解析:构建社区站点 (Community Sites)

精通 Salesforce Email Studio:咨询顾问指南之 AMPscript 与数据扩展实现动态个性化邮件