今回は親子関係をもったEntityのUpdateを中心に解説する。例によって、請求書アプリを題材にしている。ソースは=>ココで、使用しているReflexGaeライブラリは=>ココ
親子関係をもつEntityのUpdate
請求書アプリでは、請求書1枚がEntity1インスタンスとなるように設計されている。1つの請求書(Invoice)が複数の明細レコード(Order)をもち、さらには、Invoiceを親であるInvoiceBaseがListとして複数保持している。また、InvoiceBaseはInvoiceのレコード数、および、Orderのレコード数も保持している。このような関係をownedというが、このような構造をしているのは、EntityGroupとして定義しているからで、1トランザクションで実行する必要があるからである。
これらを更新するには、下図のように、まず、クライアントから受け取ったJSONのInvoiceをオブジェクトに変換したものとDatastoreとの差分を取り、その差分を反映させたオブジェクトをあらためてPersistentにすればよい。
DatastoreをUpdateする際の注意点
* 更新でmakePersistentは必要なし
Datastoreから取得したオブジェクトはPersistentな状態である。Persistentな状態とは、Datastoreへのアクセサを保持している状態で、setterを使って値をセットするだけで、(makePersistentを呼び出さなくても)永続化されることになる。
また、所有関係にあるオブジェクトがデータストアに保存されると、そのオブジェクトと関係があるすべてのオブジェクトの内、保存する必要のあるもの(新しいオブジェクト、または最後に読み込まれてから変更されたもの)は自動的に保存される。つまり、Persistentなオブジェクトにaddすることで、親のオブジェクトは子を含めてPersistentになる。
* lazyな読み込み
Datastoreから取得したオブジェクトの子は eager loadされない(アクセサを使って参照したときのみ値を取得できる)ので、別途、子を取得して親にセットする必要がある。
* propertyの更新は1トランザクションで1回のみ許される
2回以上更新すると、「can't update the same entity twice in a transaction or operation」というエラーが起きる。
* オブジェクトの親子関係とKind(≒Table)の親子関係に関係はない
親オブジェクトに子をaddしたからといってKindの親子関係になるわけではない。Kindの親子関係を紐付けるのはKeyであり、子のKeyに親のKeyをAddすることで関係付けることができる。Keyを明示的にセットしない場合(nullの場合)はシステムが勝手にKeyをセットする。
サンプルプログラム
以下のように動作するサンプルプログラムを示す。
1.でそれぞれ取得しているのは、InvoiceBaseからInvoiceを直接取り出すのができないから。(forループでまわさないと取れない)また、lazyな読み込みなので、3.の処理が必要となる。
2.でdetachCopyしているのは、Persistentオブジェクトを直接操作するのを避けるため。Persistent直接だと、setterを1回しか呼べないという制約にもひっかかる。
1.InvoiceとInvoiceBaseのPersistentオブジェクトをそれぞれ取得する
2.invoicePersistentから、いったんdetachCopy
3.コピーしたものに子要素のorderを追記補完
4.invoiceからinvoiceSource(1品一葉)を取得する。
5.クライアントからのリクエストデータで更新があったものだけをinvoiceTargetにコピーする
6.Revisionを更新
7.InvoiceBaseにaddすることでInvoice以下子要素のorderなどもpersistentになる
AJAX CRUDサンプルとJDO代替ライブラリ
RESTfulアプリのCRUDサンプル -Modeling編-
RESTfulアプリのCRUDサンプル -Servlet編-
Entityとトランザクション
0 件のコメント:
コメントを投稿