AppEngineでは、データがapplicationIdを持っています

Google App Engine for Java
hogeというIDのアプリケーションで作成したデータを、
fugaというIDのアプリケーションに投入にするには?

bulkloader ですよね。
Appengine Bulkloader IO 2010

自分はAppEngineは、Javaのほうを使っているんですが、
このbulkloader(appcfg.py)は便利に使っています。*1
・・・が、ちょっとつまづいたのでメモ。

hugaアプリケーションで動作確認をしたら、
こんなエラーメッセージを出されました。

app fuga cannot access app hoge's data
えー?データがアプリケーションID持っているんだっけ?
はい、そうみたいです。

参考リンク:
BadRequestError: app * cannot access app * data

そしてアプリケーションIDをまたいでデータを移す場合には、
bulkloader がそのへんよろしくやってくれているとのこと。
ふむふむ確かに、いままで開発中さんざんbulkloaderを使ってきたけど、
ふつうにアプリケーションIDをまたいでデータを使い回せていた。

で、自分のソースコードを改めてよくみてみると、


a) エンティティFoo が、別のエンティティBar の実体を、プロパティとしてまるごと保持している。Bar のKeyも込みで。
b) その、保持されるエンティティBar が、また別なエンティティへの外部キーを複数、リストプロパティで保持している。
この、b) の、外部キーを使ってgetするところでエラーになっていました。
うんうん、これはだめだろうな。いかにbulkloaderといえどもシリアライズされたBlobなデータをひもといて
アプリケーションIDのケアしてくれるわけないよね。

さて、どう直すべきか。
この、エンティティBar は、いちおうDatastore上に永続化されるんですが、
いわばセッション的な使い捨てデータです。
ただ、エンティティFoo に関連付けられた場合は、永続すべき価値を持つ、というものなんです。
なので、

  • エンティティFoo がエンティティBar の実体をプロパティとして保持するのをやめて
  • エンティティBaz という、Barとインターフェースを同じくするクラスのを作って、Barの値はこっちに移したうえで永続化する。
  • エンティティFoo はBaz への参照(Slim3のModelRef)を保持する
という方式に変えてみました。これでbulkloaderによるデータの可搬性を確保できました。

うーーむ。要はRDB的にしたっていうことか。なんか爽快感がないな。
いちトランザクションで永続化するエンティティBaz が増えたので、
つまりSlim3のグローバルトランザクションの参加メンバーが増えてしまったしね。


というか、最初の実装が駄目であることにいまひとつ納得がいかない。

いずれにせよ、「Keyを含むBlobデータには注意すべし」ですね。


※探したら、ほかにこんなフィールドをモデルクラスに持たせていました。これも、別な方法で修正しました。

@Attribute(lob = true)
private Map hogehotes = new LinkedHashMap();

*1:namespaceは、未定義です。