以前からぼちぼち書いていたこっちの記事が先に出来上がったので公開します。
■そのまま比較するのはいくら何でもアレですが■
今まで15年ぐらいMySQL使っていたと思うのですが、今日はじめてMySQL Workbenchを使ってみました。例によってマニュアル読まないのでとっつきにくかったけど、馴染んでしまえば楽勝。やっぱローカルサーバはサクサク動いていいですわ。
Salesforceは、というか、やっぱりWebアプリって、どうしてもサクサク感が足りない。日本にデータセンターできてWebでのレスポンスはよくなったものの、それでも「query」っていうレスポンス感ではないように思います。
Amazon RDSなどクラウド上で動いているMySQLサービスなんてのもあるけど、あれはどうなんでしょ。使ったことのある方いらっしゃいます? まぁ素のqueryとユーザ権限などてんこ盛りにかぶさったForce.com APIを同列に比べてはいけませんけども。
■Force.comからmySQLへ■
先日、Force.com APIで動かしていたFlashアプリをMySQLに移行するというお仕事をしました。一応、互換レイヤを作っておいてサクっと移行のはずですが予期せぬデータ変換トラブルが出るのは業界のお約束でございます。「お約束」ではすまない、とても大変なことになったのですが、その辺は長いので省略。関係者の皆様に改めて御礼とお詫びを申し上げる次第でございます。
その経験を元に、FlashでForce.comあるいはmySQLをアクセスしまくる方法、について簡単にまとめてみたいと思います。
■使用ライブラリ■
以下のライブラリが必要です。swcをダウンロードしてAIRプロジェクトのlibsに入れます。
- MySQL用ライブラリ
- Force.com
■Connection/AsyncResponder■
割と似てます。当然Force.comではサーバ指定とポート指定は不要でid, passwordを渡してやればつながります。
mySQL:
mysql = new com.maclema.mysql.Connection("<サーバ>", 3306, "<接続名>", "<ユーザ>", "<パスワード>");
mysql.addEventListener("connect", handleConnected);
mysql.addEventListener("ioError" , errorConnected);
mysql.connect();
..
private function handleConnected(e:Event):void {
trace( "connection success" );
}
..
private function errorConnected(error:Event):void {
trace( "connection error" );
trace( e.toString() );
}
Force.com:
var lr:LoginRequest = new LoginRequest();
lr.username = "<force.com id>";
lr.password = "<password><signature>";
lr.callback = new com.salesforce.AsyncResponder(loginHandler, faultHandler);
force.login(lr);
..
private function loginHandler(result:LoginResult, inObject:Object):void {
trace("login success");
}
..
private function faultHandler(result:Fault):void {
trace(result.faultcode);
trace(result.faultstring);
}
Force.com/mySQLを一本化する場合に一つ問題があります。それは、asSQLはmx.rpc.AsyncResponderを使いますが、Force.comは同じ名前のcom.salesforce.AsyncResponderを使うという点。名前が違うだけなら、宣言と生成でフルパス指定すれば済むんですが、困ったことにコールバック関数の引数の数が違います。もちろん1本のソースコードでmySQLとforce.comに対応、なんてことをやらなければ全然問題ないんですけども。
■Fetch■
MySQL:
var st:Statement = mysql.createStatement();
st.executeQuery("SET NAMES 'UTF8'");
st.sql = "SELECT Id, Name FROM SomeTable__c";
var token:MySqlToken = st.executeQuery();
token.addResponder(new mx.rpc.AsyncResponder(queryHandlerSomeTable, fault, token));
..
private function queryHandlerSomeTable(data:Object, token:Object):void {
var rs:ResultSet;
rs = ResultSet(data);
while( rs.next() ) {
trace(rs.getString("Id"));
trace(rs.getString("Name"));
}
}
Force.com:
strQuery = "SELECT Id, Name FROM SomeTable__c";
force.query(strQuery, new com.salesforce.AsyncResponder(queryHandler, faultHandler));
..
private function queryHandlerSomeTable(result:QueryResult):void {
if (result != null && result.records != null && result.records.length > 0) {
for each (var item:SObject in result.records) {
trace(item.Id);
trace(item.Name);
}
}
if (!result.done) {
force.queryMore(result.queryLocator,
new com.salesforce.AsyncResponder(queryHandlerSomeTable,
faultHandler));
}
}
単純なfetchなら話は簡単でSOQLとSQLもまったく同じになります。問題はリレーションを使う場合です。force.comはオブジェクト型なので Account.Name って書くだけで取引先名を引っ張ってこれますが(WebObjectsもそうだったなぁと遠い目)、mySQLはJoinで表を結合してAccount.Name には適当なエイリアス名を付けて参照する必要があります。このへん需要があれば詳しく書きますのでコメントください(ない、というオチが寂しい)。
■Update/Insert
需要があれば書きます。
fetchした結果はどっちもObject型みたいなもんに入って返って来ます。で、どっちもSQL/SOQLのattribute名とObjectから引っ張り出す時のkeyが間違っていると、fetchしたのにnullだったのか、SELECT文に書き忘れてnullだったのか、すぐにはわかりません。大文字と小文字を間違えてもダメです。SELECT文に書いた通りのkeyと完全に一致しないとダメです。Objectにkeyがあるかどうかを確認して、あるはずのkeyがなかったらエラーを出す、というような処理をはさみましょう。
まぁね…当たり前のことなんだけどね…。
■Force.comでのはまりどころ■
Flashとは違ってAIRで使う場合はデフォルトで同期がONになっています。ので、Fetch後に自動的にForce.com APIに対して問い合わせをします。しかし、相手はForce.com、頻繁に問い合わせするもんであっという間に1日のアクセス制限回数を超えてしまいます。ログイン前にでも以下の行を実行してキャッシュ切ってください。
force.doCache = false;
update文でprimary keyの値を指定しますが…その値の型が間違っていた場合には、「success側のコールバック関数にfailが帰ってくる」という何が何だかわからない現象が起こります。これ気づくのに2時間ぐらいかかりました…だってねぇ…まさかねぇ…。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。