お気に入り | 日本語 | ログイン

データの作成、取得、削除

JDO データ オブジェクトのデータストアへの保存は、PersistenceManager インスタンスの makePersistent() メソッドを使用して簡単に行えます。App Engine の JDO 実装では、オブジェクトの主キー フィールドを使用して、どのデータストア エンティティがどのデータ オブジェクトに対応するかを管理しています。また、新しいオブジェクトのキーは自動的に生成できます。キーを使用すると、エンティティをすばやく取得できます。キーは、既知の値(たとえばアカウント ID)から生成できます。

オブジェクトの永続化

単純なデータ オブジェクトをデータストアに格納するには、PersistenceManager の makePersistent() メソッドを呼び出してインスタンスを渡します。

        PersistenceManager pm = PMF.get().getPersistenceManager();

        Employee e = new Employee("Alfred", "Smith", new Date());

        try {
            pm.makePersistent(e);
        } finally {
            pm.close();
        }

makePersistent() の呼び出しは同期的に処理されるため、オブジェクトが保存されてインデックスが更新されるまでは返されません。

複数の JDO オブジェクトを保存するには、makePersistentAll(...) メソッドを呼び出してオブジェクトのコレクションを渡します。この処理は、現行のリリースでは一連の makePersistent() 呼び出しのような形で実装されていますが、将来のリリースではより効率的なバッチ呼び出しとして実装される予定です。

注: 保存するデータ オブジェクトのいずれかの永続フィールドが他の永続データ オブジェクトを参照しており、これらのオブジェクトのいずれかが一度も保存されたことがないか、読み込みの後に変更されている場合は、参照先のオブジェクトもデータストアに保存されます。詳しくは、関係をご覧ください。

キー

すべてのエンティティには、App Engine 内の全エンティティの中で、そのエンティティを一意に特定するためのキーがあります。完全なキーには、アプリケーション ID、種類、エンティティ ID など、さまざまな情報が含まれています(キーにはエンティティ グループに関する情報も含まれています。詳しくは、トランザクションをご覧ください)。

オブジェクトのキーは、インスタンスのフィールドに格納されます。主キーは、@PrimaryKey アノテーションで指定します。

キーの ID 部分は、アプリケーションでオブジェクトを作成するときに文字列として指定する方法と、データストアで数値の ID を自動的に生成する方法があります。完全なキーは、データストア内のすべてのエンティティの間で一意でなければなりません。つまり、種類が同じでエンティティ グループの親も同じオブジェクトが複数ある場合は、それらのオブジェクトの間で一意なキーをそれぞれのオブジェクトに割り当てる必要があるということです。キーの動作は、フィールドの型とアノテーションを使用して指定できます。

あるクラスが関係内で「子」クラスとして使用されている場合、キー フィールドの型はエンティティ グループの親を表すことのできるもの、つまり Key インスタンスか、文字列としてエンコードされた Key 値にする必要があります。エンティティ グループに関する詳しい情報はトランザクションを、関係に関する詳しい情報は関係をご覧ください。

ヒント : アプリケーションで新しいオブジェクトを作成し、同じ種類を持つ(そして同じエンティティ グループの親を持つ)別のオブジェクトと同じ文字列 ID を割り当てた場合、新しいオブジェクトを保存するとデータストア内の既存のオブジェクトが上書きされます。新しいオブジェクトを作成する前に文字列 ID がすでに使用されているかどうかを確認するには、その ID でエンティティを取得するトランザクションを実行します。取得が失敗すれば、その ID で新しいオブジェクトを作成できます。詳しくは、トランザクションをご覧ください。

主キー フィールドの型は以下の 4 つです:

Long

データストアによって自動的に生成されるエンティティ ID は長整数型(java.lang.Long)です。この型は、エンティティ グループの親がなく、ID をデータストアで自動生成する必要のあるオブジェクトに使用します。Long 型のキー フィールドは、インスタンスを保存するときに値が設定されます。

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
エンコードされていない文字列

アプリケーションでオブジェクトの作成時に付与するエンティティ ID(「キー名」)は文字列型(java.lang.String)です。この型は、エンティティ グループの親がなく、ID をアプリケーションで設定する必要のあるオブジェクトに使用します。アプリケーションでは、エンティティを保存する前に、このフィールドに任意の ID を設定できます。

import javax.jdo.annotations.PrimaryKey;

// ...
    @PrimaryKey
    private String name;
Key

Key インスタンス(com.google.appengine.api.datastore.Key)です。キーの値は、エンティティ グループの親がある場合はそのキーと、アプリケーションで割り当てた文字列 ID またはシステムで生成した数値 ID を組み合わせたものになります。アプリケーションで割り当てた文字列 ID でオブジェクトを作成するには、その ID で Key 値を作成し、その値をキー フィールドに設定します。システムで割り当てた数値 ID でオブジェクトを作成する場合は、キー フィールドを null のままにします(エンティティ グループの親の使用方法については、トランザクションをご覧ください)。

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;

// ...
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

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

アプリケーションでは、次のように KeyFactory クラスを使用して Key インスタンスを生成できます:

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

// ...
        Key key = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");
        Employee e = new Employee();
        e.setKey(key);
        pm.makePersistent(e);
エンコードされた文字列としてのキー

Key と似ていますが、値がエンコードされた文字列形式のキーです。エンコードされた文字列のキーを使用すると、App Engine データストアのエンティティ グループを活用しつつ、移植しやすいアプリケーションを開発できます。

import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;

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

アプリケーションでは、名前付きのキーを使用して保存前にこの値を設定するか、null のままにしておくことができます。エンコードされたキー フィールドが null の場合は、オブジェクトの保存時にシステムで生成されたキーがフィールドに設定されます。

Key インスタンスとエンコードされた文字列表現は、KeyFactory クラスの keyToString() および stringToKey() メソッドを使用して相互に変換できます。

エンコードされたキー文字列を使用すると、次のように追加フィールドを使って、オブジェクトの文字列 ID または数値 ID へのアクセスを提供できます:

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

    @Extension(vendorName="datanucleus", key="gae.pk-name", value="true")
    private String keyName;

    // OR:

    @Extension(vendorName="datanucleus", key="gae.pk-id", value="true")
    private Long keyId;

"gae.pk-name" フィールドには、オブジェクトを保存する前にキー名を設定できます。オブジェクトの保存時には、そのキー名を含む完全なキーが、エンコードされたキー フィールドに設定されます。型は String でなければなりません。

"gae.pk-id" フィールドはオブジェクトの保存時に設定され、その値を変更することはできません。型は Long でなければなりません。

生成されたキー(valueStrategy = IdGeneratorStrategy.IDENTITY を使用したキー フィールド)で新しいオブジェクトを作成する場合、当初のキー値は null になります。オブジェクトがデータストアに書き込まれると、キー フィールドに値が設定されます。トランザクションを使用している場合は、トランザクションがコミットされるとオブジェクトが書き込まれます。それ以外の場合は、オブジェクトの作成時に makePersistent() メソッドが呼び出されたとき、またはオブジェクトの更新時に PersistenceManager インスタンスの close() メソッドが呼び出されたときにオブジェクトが書き込まれます。

キーの作成と使用

アプリケーションでは、あるエンティティの完全なキーのすべての要素がわかっていれば、オブジェクトがない場合でも対応する Key オブジェクトを作成できます。

エンティティ グループの親がないエンティティのキーの場合は、KeyFactory クラスの静的メソッド createKey() を使用できます。このメソッドは、種類(クラスの簡略名)と、アプリケーションで割り当てられた文字列 ID またはシステムで割り当てられた数値 ID のどちらかを取り、Key オブジェクトを返します。たとえば、種類が "Employee" でキー名が "Alfred.Smith@example.com" のエンティティ(エンティティ グループの親はなし)のキーを再作成するには次のようにします:

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

// ...
        Key k = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");

種類が "Employee" で、システムで割り当てた数値 ID が 52234 のエンティティ(エンティティ グループの親はなし)のキーを再作成するには次のようにします:

        Key k = KeyFactory.createKey(Employee.class.getSimpleName(), 52234);

Key と文字列表現は、KeyFactory クラスの keyToString() および stringToKey() メソッドを使用して相互に変換できます(このメソッドは、デバッグを目的に人間が解読可能な値を返す Key クラスの toString() メソッドとは異なります)。

エンティティ グループの親があるエンティティのキーの場合は、KeyFactory.Builder クラスを使用できます:

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

// ...
        Key k = new KeyFactory.Builder(Employee.class.getSimpleName(), 52234).addChild(ExpenseReport.class.getSimpleName(), "A23Z79").getKey();

Builder インスタンスの addChild() メソッドは Builder を返すため、連続的に呼び出すことでキー パスの各要素を追加できます。特定の Builder の完全な Key 値を取得するには、その Builder の getKey() メソッドを呼び出します。

エンティティ グループに関する詳しい情報は、トランザクションをご覧ください。

キーによるオブジェクトの取得

キーを指定してオブジェクトを取得するには、PersistenceManager の getObjectById() メソッドを使用します。このメソッドは、次のようにオブジェクトのクラスとキーを取ります:

        Key k = KeyFactory.createKey(Employee.class.getSimpleName(), "Alfred.Smith@example.com");
        Employee e = pm.getObjectById(Employee.class, k);

クラスが使用するキー フィールドが文字列 ID(String)または数値 ID(Long)である場合、getObjectByID() は次のようにキー パラメータとして単純値を取ります:

        Employee e = pm.getObjectById(Employee.class, "Alfred.Smith@example.com");

キー引数としては、サポートされているキー フィールド型(文字列 ID、数値 ID、Key 値、またはエンコードされたキー文字列)を指定できます。この引数の型は、クラス内のキー フィールドの型と違っていても構いません。App Engine では、クラス名と指定した値に基づいて完全なキーを生成できなければなりません。文字列 ID と数値 ID は排他的であるため、数値 ID による呼び出しで文字列 ID のエンティティが返されることはありません。Key 値またはエンコードされたキー文字列が使用されている場合は、そのキーで参照するエンティティの種類はそのクラスで表現されていなければなりません。

オブジェクトの更新

JDO オブジェクトを更新する方法の 1 つとして、オブジェクトをフェッチして PersistenceManager からオブジェクトが返されたら、PersistenceManager が開いたままの状態でオブジェクトを修正する方法があります。この場合、PersistenceManager を閉じると変更が永続化されます。次に例を示します:

public void updateEmployeeTitle(User user, String newTitle) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    try {
        Employee e = pm.getObjectById(Employee.class, user.getEmail());
        if (titleChangeIsAuthorized(e, newTitle) {
            e.setTitle(newTitle);
        } else {
            throw new UnauthorizedTitleChangeException(e, newTitle);
        }
    } finally {
        pm.close();
    }
}

この Employee インスタンスは PersistenceManager によって返されたものであるため、Employee の永続フィールドに加えたすべての修正は PersistenceManager によって認識されており、PersistenceManager を閉じると自動的にデータストアが更新されます。このような認識が可能なのは、Employee インスタンスが PersistenceManager に「アタッチ」されているからです。

クラスを「デタッチ可能」と宣言すると、PersistenceManager を閉じてからオブジェクトを修正できます。そのためには、次のように @PersistenceCapable アノテーションに detachable 属性を追加します:

import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;

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

これで、Employee オブジェクトを読み込んだ PersistenceManager が閉じられ、このオブジェクトのフィールドを読み書きできる状態になります。次の例では、デタッチしたオブジェクトがいかに便利かを示します:

public Employee getEmployee(User user) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    pm.setDetachAllOnCommit(true);
    try {
        e = pm.getObjectById(Employee.class, "Alfred.Smith@example.com");
    } finally {
        pm.close();
    }
    return e;
}

public void updateEmployeeTitle(Employee e, String newTitle) {
    if (titleChangeIsAuthorized(e, newTitle) {
        e.setTitle(newTitle);
        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            pm.makePersistent(e);
        } finally {
            pm.close();
        }
    } else {
        throw new UnauthorizedTitleChangeException(e, newTitle);
    }
}

デタッチしたオブジェクトは、データ転送オブジェクトを作成する代わりとして使用できます。デタッチしたオブジェクトの操作に関する詳しい情報は、DataNucleus のドキュメントをご覧ください。

オブジェクトの削除

オブジェクトをデータストアから削除するには、PersistenceManager の deletePersistent() メソッドを呼び出してオブジェクトを渡します:

        pm.deletePersistent(e);

オブジェクトのフィールドに永続化された子オブジェクトが含まれている場合は、その子オブジェクトも削除されます。詳しくは、関係をご覧ください。