こんにちは。このエントリはSalesforce Advent Calendarの11日目です。
ノリでSalesforce Advent Calendarに手を挙げてしまいましたが、僕自身はSalesforceでアプリを作ったことは一度もありません。VisualForceは1時間で挫折しました。
そんな人間がSalesforceのAdvent Calendarで何を語ろうと言うのかというと、SOAP APIのJavaラッパーを作ったりもしているので、それを使ったSalesforceと外部RDBMSとの同期連携について書いてみようと思います。
※タイトルは半分釣りでHeroku Postgresと書いていますが他のRDBでも多分動きます。
★ところで Heroku Connect
本題に入る前にSalesforceとHeroku Postgresの同期と言えば先日のDreamForceでHeroku Connectが発表されました。
http://blogjp.sforce.com/2013/11/heroku1-.html
今のところ予告編だけで実際に試せるのは来年以降になるらしいですが、某エバンジェリストに聞いたところでは、これはSalesforce上のオブジェクトと同じ構造のテーブルをPostgres上に作成して双方向に同期するもののようです。
ちなみにガバナ制限は受けないと某エバンジェリストは力強く言っていましたが、別の筋からはそんなの聞いてないという話もあり、真偽は定かではありません。(^^;
素晴らしいんですが、この枠組みだとまずSalesforceアプリありきなので、既存のHerokuアプリのデータをSalesforceに取り込みたい場合は使いにくいかもしれません。
今時のクラウドデータベースではストレージ容量は十分過ぎる程にあるので、アプリで使用するテーブルとSalesforceと同期するテーブルはきっぱり分離してPostgres内でトリガーで同期するというアプローチはアリだと思いますが、自前のテーブルの方はともかく自動生成される同期テーブルにトリガーをつけて良いかどうかは謎ですね。。。
それにこのやり方で完全双方向は無限ループの回避がやっかいかな?
いずれにせよ使えるようになったら試してみるつもりなのでこの話はまたいずれ。
★ところで flectSalesforce
ちょいちょいあるよー、とはこのブログでも言っていたのですがちゃんと紹介したことはなかったと思うので改めて。
http://oss.flect.co.jp/libs/ja/flectSalesforce.html
flectSalesforceはSalesforceのSOAP APIのJavaフルスクラッチ実装です。
僕は元々某所でSOAPのかなり初期からSOAPクライアント/サーバーを作ったりもしていたのでSOAPには色々と言いたいことがあるんですが、それはまぁ良いでしょう。
とにかくAxisは使いたくなかったので自分で作ることにしたんですが多分正解でした。SalesforceのSOAP実装にも色々と突っ込み所があるんですが、これまた誰の共感も得られそうにないので墓まで持っていきます。(^^;
□□□□
前置きが長くなりましたが。。。
そんなこんなでこれはSalesforce APIの実装のひとつです。必要なものから作っているので全部のメソッドを実装しているわけではありませんが、オブジェクトの更新/削除など主要なものは網羅しています。(describeLayoutやdescribeTabsみたいなメソッドを実装しても誰も使うことないでしょうしね)
元々は社内で使うことしか想定していなかったのでコメントも日本語です。(^^;
(必要最低限しか書いてませんが)
既存のAPIラッパーとの相違点としては単純なAPIのラッパーに留まらず、独自のユーティリティインターフェースを備えている点があげられると思います。
- SQLライクなINSERT, UPDATE, DELETE構文によるデータ更新
- Fixtureによるテストデータの更新、削除
- RDBからのSELECT結果をSalesforceに取り込み
- SalesforceからのSELECT結果をRDBに取り込み
などなど。
後ろの二つがここから紹介する内容です。
APIの使い方自体は
http://flect-salesforce-sample.herokuapp.com/
でサンプル付きで説明しているのでここでは主に処理の枠組みについて説明します。
★RDBからのSELECT結果をSalesforceに取り込み
http://flect-salesforce-sample.herokuapp.com/sqlsync
RDBからSELECTした結果でCSVを作り、それをBulk APIで投入します。
特徴的なのはSELECTしたフィールドとSaleforceオブジェクトのフィールドの対応をSELECT文内のエイリアスで指定するという点です。
SELECT COL1 as Col1__c, COL2 as Col2__c FROM TABLE1 WHERE ...
この仕様によりJoinや関数の使用などDBMSのサポートするすべてのSQL構文を駆使してSELECT文を書くことができます。
同期処理として運用する場合はWHERE句に更新日付で結果を絞る条件を付加して定期的に実行します。(それに特化したアプリもあります。)
項目に外部IDがあればレコードの更新方法はUPSERTになります。
ちなみにBulkAPIには1万行制限がありますがSELECT結果が1万行を超える場合は内部的にファイル分割されるので、1万行を越えても問題なくデータを取り込むことができます。
★ SalesforceからのSELECT結果をRDBに取り込み
http://flect-salesforce-sample.herokuapp.com/sobjectsync
これもBulkでやりたかったんですが、クエリ自体はSOAP APIで投げています。
何故ならBulkクエリでは参照フィールド(CreatedBy.Nameとか)が取れないからです。。。
使えねー。。。(--
サブクエリは仕方がないと思うけど、参照フィールドくらいはBulkでも取らせて欲しいよ。。。
□□□□
仕組みとしては要するにSalesforceに対してクエリを実行した結果をぐるぐる回しながら指定のキーでUPDATE文を実行し、結果が0件だったらINSERT文を実行しているだけです。
QueryMoreは内部的に処理されるので、結果セットが大きい場合も問題なく実行できます。
こちらの方ではSalesforceオブジェクトのフィールドとRDBのテーブルカラムを一つずつ指定する形式をとっています。
なのでSOQLの関数は使用できません。(あるんだっけ?(^^;;; )
その代わりSELECTした結果をJavaで加工した結果をマッピングすることができます。
request.addFunctionMapping("NAME", new SObjectSyncRequest.Function() { @Override public Object evaluate(SObject obj) { String fn = obj.getString("FirstName__c"); String ln = obj.getString("LastName__c"); return ln + fn; } });
引数のSObjectから値を取得してそれをごにょごにょと演算をした結果をreturnすればOK。データ移行の自由度はむしろこっちの方が高いです。
実行結果の詳細なハンドリングを行いたい場合はListenerクラスを組み込むことで個別にエラーとなったオブジェクトをハンドルすることができます。
□□□□
こんな感じで雰囲気は伝わったでしょうか?
Heroku Connectが完全自動で固定的なのに対して、こちらの方は自由度高くプログラムに組み込めるのが特徴と言えると思います。
実際のところ、これらの機能は社内要件から実装したものであって公開して誰でも使えるようにしているのは、もののついでという感はあるのですが。。。(^^;
ご意見、ご要望等あればGithubのIssue、Twitter等に書いてくれれば可能な範囲で対応するので、定常的な同期に限らずワンショットのデータ移行の場合などでも思いだしたら使ってみてくだされ。(^^)/