2011年2月10日木曜日

Slim3でDatastoreを使う - データ定義編

 

この記事はこちらへ移動しました。
Slim3でDatastoreを使う

 

モデルの定義

データのクラスに@Modelアノテーションを付ける
永続化するプロパティには getter, setter が必要
永続化しないフィールドには@Attribute(persistent = false) アノテーションを付ける

フィールドの型

フィールドで使える型はDatastoreの基本型、基本型のコレクション、シリアライズ可能なオブジェクト
フィールドで使える基本型 → Core Value Types
シリアライズ可能なオブジェクトはBlob型として格納される(@Attribute(lob = true)を付ける)
500文字(byte[]は500バイト)を超えるフィールドには@Attribute(lob = true)を付ける
配列はコレクションとして扱われない(シリアライズしてBlobになる?)
インデックスに対応した型はデフォルトでインデックスが付く
インデックスを付けたくないフィールドには@Attribute(unindexed = true)を付ける

サポートするコレクション型

ArrayList, LinkedList, HashSet, LinkedHashSet, TreeSet, List (ArrayList), Set (HashSet), SortedSet (TreeSet)

()内はプロパティから返される実際のインスタンスの型

自動的なプロパティ値の更新

@Attribute(listener = ???) アノテーションで値を自動更新するリスナを指定できる

保存するたびに更新

@Attribute(listener = ModificationDate.class)
Date updatedAt;

最初の保存のときだけ更新

@Attribute(listener = CreationDate.class)
Date createdAt;

キー

モデルクラスに1つだけキーを持たなければならない
キーのフィールドには @Attribute(primaryKey = true) を付ける
キーは パス、kind、ID によって構成される
kind はクラスの単純名から付けられる
kindはクラスの @Model(kind = "...") アノテーションで変更可能
IDはアプリケーションで指定した文字列か、Datastoreが付けた数値(キーをnullのまま保存)
キーは Datastore.createKey(Class, String) で作成してキープロパティにセットする

エンティティグループ

エンティティの親子関係はキーを作成するときに親エンティティのIDを指定することで決定する
プロパティに他のエンティティの参照を持ってもエンティティグループに入れるわけではない
エンティティの親子関係はあとで変えることはできない
先祖エンティティが削除されても子孫エンティティは削除されない

リレーションシップ

片方向1対1関連

ModelRef型のプロパティを作って次のように初期化とgetterメソッドを作成。

@Model public class Address { … }

@Model public class Employee {
    private ModelRef<Address> addressRef = new ModelRef<Address>(Address.class);
    public ModelRef<Address> getAddressRef() { return addressRef; }
}

インスタンスを作成して関連付けして保存

Address address = new Address();
Employee employee = new Employee();
employee.getAddressRef().setModel(address);
Datastore.put(address, employee);

ロードするときは、

Employee employee = Datastore.get(Employee.class, employeeKey);
Address address = employee.getAddressRef().getModel();

参照先はレイジーロードされる。

双方向1対1関連

先ほどの関連に逆方向の参照を追加。逆方向はInverseModelRef型にする。逆方向の参照は永続化しない。Addressクラスに以下のコードを追加。

@Attribute(persistent = false)
private InverseModelRef<Employee, Address> employeeRef = new InverseModelRef<Employee, Address>(Employee.class, "addressRef", this);

public InverseModelRef<Employee, Address> getEmployeeRef() { return employeeRef;}

これでAddressからEmployeeへの参照ができる。

address.getEmployeeRef.getModel();

プロパティに関連をセットするには正方向側(Employee側)のプロパティにセットする。逆方向にはsetModel()メソッドが無い。

片方向多対1関連

多 → 1 の参照を持つ関連の場合、片方向1対1の場合と同じ。

双方向多対1関連

多 → 1への参照に加え、1 → 多 への参照を追加。1側から多側への参照は永続化しない。

@Attribute(persistent = false)
private InverseModelListRef<Employee, Department> employeeListRef = new InverseModelListRef<Employee, Department>(Employee.class, "departmentRef", this);

public InverseModelListRef<Employee, Department> getEmployeeListRef() {…}

1側から多側を取得する場合は次のようにする。

List<Employee> employeeList = department.getEmployeeListRef().getModelList();

双方向多対多関連

関連クラスを作って、1 ← 多(関連クラス) → 1 のようにする。

関連クラスに1側への参照プロパティをそれぞれ作る。

@Model
public class EmployeeProject {
    …
    private ModelRef<Employee> employeeRef = new ModelRef<Employee>(Employee.class);
    private ModelRef<Project> projectRef = new ModelRef<Project>(Project.class);

    public ModelRef<Employee> getEmployeeRef() {…}
    public ModelRef<Project> getProjectRef() {…}
    …
}

1側は"双方向多対1"の逆参照と同様。EmployeeProjectに対して永続化しない InverseModelListRef<EmployeeProject, 1側クラス> のプロパティとgetterを作る。

ロードするときは片側(たとえばProjectオブジェクト)から関連オブジェクトのリストを取得して、関連オブジェクトから反対側のオブジェクトを得る。

relObject = project.getEmployeeProjectRef().getModelList();
relObject.getEmployeeRef().getModel();