ひがやすを技術ブログ

電通国際情報サービスのプログラマ

GAEでunownedな関連を定義する方法

Google App Engineでは、関連の実装として、キーの親子関係で実現するownedな関連と、キーの親子関係ではなく、単に相手のキーを持つだけのunownedな関連があります。
unownedな関連は、RDBMSにおけるFKを持っているようなものだと思うとイメージしやすいと思います。


例えば、次の例では、FooがBarをunownedな関連先として定義しています。


@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Foo {

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String key;

@Persistent
private String barKey;

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public String getBarKey() {
return barKey;
}

public void setBarKey(String barKey) {
this.barKey = barKey;
}
}


@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Bar {

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String key;

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}
}


これが基本。でも、FooからBarを取得しようとしたときに、キーしかもっていないので、何かと不便です。特に、JSPでFooのインスタンスからBarを取得しようとすると路頭に迷います。
unownedな関連を実現するときは、次のようにするのがお勧めです。ポイントは、barKeyプロパティではなく、仮想的なbarプロパティを使うところ。これで、関連を自然な形で扱うことができます。


@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Foo {

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String key;

@Persistent
private String barKey;

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public Bar getBar() {
if (barKey == null) {
return null;
}
return JDOHelper.getPersistenceManager(this).getObjectById(Bar.class, barKey);
}

public void setBar(Bar bar) {
if (bar == null) {
barKey = null;
}
barKey = bar.getKey();
}
}


JDOHelper.getPersistenceManager(this)でPersistenceManagerが取得できるのは、モデルがpersistentな状態(detachedな状態になったらだめ)のときだけです。
persistence.xmlでdetachOnCommitがtrueになっているとcommitされたときにdetached状態になってしまうので、falseにしておきましょう。
また、リクエストを処理している間、モデルがpersistentな状態でいられるようにFilterでPersistenceManagerを管理するといいでしょう。Slim3はそうなってます。
これでJSPでは、${foo.bar.key}のような感じで簡単にアクセスできます。