背景と応用シーン
現代の企業システムは、Salesforce を中心としながらも、ERP、データウェアハウス、自社開発のレガシーシステムなど、複数のシステムにデータが分散していることが一般的です。これらのデータを Salesforce 上で統合的に活用しようとする場合、従来はETL (Extract, Transform, Load) ツールを用いてデータを定期的に Salesforce へコピーする方法が主流でした。しかし、このアプローチには、データ同期のタイムラグ、ストレージコストの増大、そして二重のデータ管理という課題が伴います。
ここで登場するのが Salesforce Connect の中核機能である External Objects (外部オブジェクト) です。External Objects は、Salesforce の組織内にデータを物理的に保存することなく、外部システムにあるデータにリアルタイムでアクセスするための仕組みです。Salesforce の標準オブジェクトやカスタムオブジェクトとほぼ同様に、リストビューでの表示、レコード詳細ページの閲覧、グローバル検索、さらにはレポートやダッシュボードでの活用が可能です。これは「データ仮想化」というアプローチであり、データを「その場」に置いたまま活用することを可能にします。
私たち Salesforce Integration Engineer (Salesforce 統合エンジニア) にとって、External Objects はデータ連携パターンを選択する際の強力な選択肢の一つです。例えば、以下のようなシーンでその真価を発揮します。
- 大規模なデータセットへのアクセス:ERPシステムに保存されている数百万件以上の注文履歴や製品カタログなど、Salesforceのストレージ制限を考慮するとコピーが現実的でないデータへのアクセス。
- リアルタイム性の要求:外部の在庫管理システムにある最新の在庫情報を、Salesforce の営業担当者が商談作成時にリアルタイムで参照する必要があるケース。
- データの単一性維持:規制やコンプライアンスの観点から、特定のデータを組織外のシステム(Source of Truth)に保持し続けなければならない場合。
このように、External Objects はデータの移動を伴わずに、Salesforce の強力な UI とプラットフォーム機能を外部データに対して拡張するための、洗練されたソリューションです。
原理説明
External Objects がどのようにして外部データへのリアルタイムアクセスを実現しているのか、その技術的な仕組みを解説します。中核となるのは External Data Source (外部データソース) と、それに紐づくアダプタです。
ユーザーが外部オブジェクトのレコードを表示しようとしたり、SOQL でクエリを実行したりすると、Salesforce Platform はそのリクエストを External Data Source に渡します。External Data Source は、設定されたアダプタを用いて、リクエストを外部システムが理解できる形式(例:OData クエリや REST API コール)に変換し、外部システムへ送信します。外部システムからのレスポンスは、再びアダプタによって Salesforce が解釈できる形式に変換され、ユーザーに返されます。この一連のプロセスがリアルタイムで行われるため、ユーザーはまるで Salesforce 内のデータを操作しているかのように感じることができます。
この接続を実現するためのアダプタには、主に2つの種類があります。
1. OData (Open Data Protocol) アダプタ
OData は、RESTful API を構築・利用するための ISO/IEC 承認のオープンスタンダードです。外部システムが OData 2.0 または 4.0 のエンドポイントを公開している場合、Salesforce 側ではコーディング不要で External Data Source を設定するだけで接続が完了します。これは最もシンプルで推奨される方法です。接続先のエンドポイント URL と認証情報を Named Credential (指定ログイン情報) に設定することで、セキュアな接続を容易に確立できます。
2. Custom Apex Adapter (カスタム Apex アダプタ)
外部システムが OData をサポートしていない、あるいは独自の複雑な API 仕様を持つ場合に選択するのが、Apex Connector Framework を使用したカスタムアダプタの開発です。これは、私達 Integration Engineer の腕の見せ所です。Apex を用いて DataSource.Provider および DataSource.Connection といった特定のインターフェースを実装することで、Salesforce からのデータ要求(クエリ、検索など)を外部システムの任意の API へのコールに変換するロジックを自由に記述できます。これにより、SOAP, REST を問わず、ほぼ全ての Web サービスとの連携が可能になります。
このアプローチでは、データの取得 (Query)、検索 (Search)、さらには DML 操作 (Create, Update, Delete) のロジックを Apex コードで実装し、外部システムとの間の「通訳者」を作成します。
示例代码
ここでは、外部システムが OData をサポートしていないケースを想定し、Apex Connector Framework を使用してカスタムの External Data Source を作成する際のサンプルコードを示します。このコードは、外部のデータソースへの接続ロジックを定義するものです。
まず、データソースの基本的な情報や機能を定義する DataSource.Provider を実装します。
/**
* MyCustomProvider クラスは、データソースの機能を定義します。
* 主に、認証方式や、このコネクタがどのような操作(クエリ、検索など)をサポートするかを宣言します。
*/
public class MyCustomProvider extends DataSource.Provider {
// このデータソースがサポートする認証方式を返します。
// ここでは Named Credential (指定ログイン情報) を使用することを宣言しています。
override public List<DataSource.AuthenticationCapability> getAuthenticationCapabilities() {
List<DataSource.AuthenticationCapability> capabilities = new List<DataSource.AuthenticationCapability>();
capabilities.add(DataSource.AuthenticationCapability.OAUTH);
return capabilities;
}
// このデータソースがサポートする操作を返します。
// ROW_QUERY: SOQL の WHERE 句などによる基本的なクエリ操作をサポートします。
// SEARCH: SOSL による検索をサポートします。
override public 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;
}
// 実際の接続ロジックを持つ Connection クラスのインスタンスを返します。
override public DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) {
return new MyCustomConnection(connectionParams);
}
}
次に、実際のデータ操作ロジックを担う DataSource.Connection を実装します。以下のコードでは、クエリの実行部分 (query) に焦点を当てています。
/**
* MyCustomConnection クラスは、外部システムとの実際の通信ロジックを実装します。
*/
public class MyCustomConnection extends DataSource.Connection {
private DataSource.ConnectionParams connectionParams;
// コンストラクタ
public MyCustomConnection(DataSource.ConnectionParams connectionParams) {
this.connectionParams = connectionParams;
}
/**
* Salesforce からの SOQL クエリを受け取り、外部システムへの API コールを実行し、
* 結果を Salesforce が理解できる形式 (DataSource.TableResult) で返します。
* @param queryContext クエリに関するコンテキスト情報(対象テーブル、フィルタ条件など)
* @return 外部システムから取得したデータを含むテーブル結果
*/
override public DataSource.TableResult query(DataSource.QueryContext queryContext) {
// 外部データソースに定義されたテーブル名を取得
String externalTableName = queryContext.tableSelection.table;
// 外部 API のエンドポイントを構築
// Named Credential を利用して、エンドポイントと認証情報を安全に管理します。
String endpoint = 'callout:My_External_System/api/data/' + externalTableName;
// HTTP リクエストを作成
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod('GET');
// HTTP コールアウトを実行
Http http = new Http();
HttpResponse res = http.send(req);
// レスポンスをパースして、結果テーブルを作成
// 実際には、JSON.deserialize などを使用してレスポンスを解析します。
// ここではサンプルとして静的なデータを返します。
List<Map<String, Object>> responseData = new List<Map<String, Object>>();
Map<String, Object> row1 = new Map<String, Object>();
row1.put('ExternalId', 'E1001');
row1.put('Name', 'Sample Record 1');
row1.put('Amount', 150.0);
responseData.add(row1);
// 取得したデータを DataSource.TableResult 形式で返却
DataSource.Table table = DataSource.Table.get(externalTableName, 'Name');
DataSource.TableResult result = DataSource.TableResult.success(queryContext.tableSelection, table, responseData);
return result;
}
// search() や sync() などの他のメソッドも必要に応じてオーバーライドします。
override public List<DataSource.TableResult> search(DataSource.SearchContext searchContext) {
// SOSL 検索のロジックをここに実装します
return null;
}
}
注意事项
External Objects は非常に強力ですが、その特性を理解せずに使用するとパフォーマンス問題や予期せぬエラーに繋がることがあります。以下の点に注意が必要です。
権限とセキュリティ
External Objects も通常のオブジェクトと同様に、プロファイルや権限セットでオブジェクトレベル、項目レベルのセキュリティを設定します。しかし、データへのアクセス可否を最終的に決定するのは外部システム側の認証・認可です。Named Credential (指定ログイン情報) で設定された認証情報(ユーザー)が外部システムで持つ権限が、Salesforce ユーザーが実行できる操作の上限となります。例えば、Salesforce 側で編集権限を与えても、Named Credential のユーザーが外部システムで参照権限しか持たない場合、更新は失敗します。
API 制限 (Callout Limits)
External Objects に対するすべての操作(レコード表示、検索、レポート実行)は、Salesforce の API Callout を消費します。1つのクエリが複数の Callout を消費することもあります。特に、多くのユーザーが利用するリストビューやレポートで外部オブジェクトを使用すると、組織の Callout 制限(24時間あたりの上限)に短時間で達してしまうリスクがあります。利用状況は「設定 > 外部データソース」から監視し、慎重な設計が求められます。
パフォーマンスとデータ量
レスポンスタイムは、外部システムの性能とネットワークのレイテンシーに完全に依存します。外部システムの応答が遅い場合、Salesforce 上でのページ表示も当然遅くなります。また、External Objects は大量のデータを一括で処理するバッチ処理には向いていません。あくまでユーザー操作に応じた個別のレコードアクセスに最適化されています。
サポートされない機能
External Objects には、標準・カスタムオブジェクトと比較して多くの機能的制約があります。以下はその一部です。
- Apex トリガーやフロー(レコードトリガーフロー)を起動できない。
- 主従関係の「詳細」側になることはできない。(参照関係は可能)
- 共有ルールやテリトリー管理など、高度な共有機能は利用できない。
- 数式項目や積み上げ集計項目で、外部オブジェクトの項目を直接参照することには制限がある。
エラーハンドリング
外部システムがダウンしている、あるいは API がエラーを返した場合、Salesforce 上のユーザーにはエラーメッセージが表示されます。カスタム Apex アダプタを実装する場合、try-catch ブロックを用いて外部システムからのエラーを適切に捕捉し、ユーザーフレンドリーなエラーメッセージを返す、あるいはリトライ処理を実装するなどの堅牢なエラーハンドリングが重要です。
まとめとベストプラクティス
External Objects は、Salesforce をデータハブとして活用し、複数のシステムにまたがる情報をシームレスに統合するための強力なデータ仮想化ツールです。データのコピーを回避し、リアルタイム性とデータの信頼性を担保できる点で、従来の ETL アプローチとは一線を画します。
私たち Integration Engineer が External Objects をプロジェクトに導入する際のベストプラクティスは以下の通りです。
- 適切なユースケースの選択:大量データのバッチ処理や複雑な業務ロジックの自動化ではなく、「リアルタイム参照」が主目的のケースに適用します。
- OData の優先:接続先のシステムが OData をサポートしている場合、開発・保守コストの観点から、カスタム Apex アダプタよりも OData アダプタを常に優先して検討します。
- Named Credential の徹底活用:認証情報のハードコーディングは絶対に避けます。Named Credential を利用することで、認証情報をセキュアに管理し、環境間の移行も容易になります。
- パフォーマンスの考慮:クエリのフィルタリングを効果的に行い、外部システム側への負荷を最小限に抑える設計を心がけます。ページネーションのサポート(サーバ駆動 or クライアント駆動)も重要な検討事項です。
- 制限の周知:プロジェクト関係者やエンドユーザーに対して、External Objects のパフォーマンス特性や機能的制約を事前に伝え、期待値を正しく設定します。
結論として、External Objects は万能の銀の弾丸ではありません。しかし、その特性と制約を深く理解し、適切なシナリオで適用すれば、開発コストを抑えつつ、ユーザーに大きな価値を提供できる、非常に効果的な統合ソリューションと言えるでしょう。
コメント
コメントを投稿