DataStore で Only ancestor queries are allowed inside transactions. のエラー

DataStore で以下のエラーが出た。

Only ancestor queries are allowed inside transactions. のエラー

ググると以下がヒット。
http://stackoverflow.com/questions/14397207/why-do-i-get-only-ancestor-queries-are-allowed-inside-transactions-error

結論としては、
トランザクション内でエンティティを取得するには AncestorQuery or Get() or GetMult() しか利用できない。

トランザクション内でクエリを発行する以上、
StrongConsistency を担保する必要がある。
ただ、Datastore が StrongConsistencyを担保できるのは AncestorQuery or Get() or GetMult() のみなので、
Query() は利用できない。

なので、
例えば、
同一kind内でkey以外のユニークなプロパティを持とうとする場合に、
トランザクション内でユニークなことを保証することはできない。

具体的な例で言うと、
User kind があって、keyが int64 で自動採番である場合に、
User kind に name をユニークで保持することはできない。
できないことはないが、実現方法が限られる。

ユニークで保持することができるケースは以下。

  1. name を key にする
  2. User kind を Ancestor で取得できるような親のkindが存在する
  3. 別kindでユニークを担保する


1.name を key にする

name をそのまま key として扱うのに抵抗がある場合は、ハッシュ化したものを key にしてもいい。
ただ、name を key にするというのは、
「keyが int64 で自動採番である」という前提条件上、不可能なので、
「User kind のkeyをnameにする」というように、
データ構造自体を変更する必要がある。

2.User kind を Ancestor で取得できるような親のkindが存在する

User kind を Ancestor で取得する場合でも、
親のkind別でユニークが担保されるだけなので、
kind 全体でユニークを担保することはできない。
そもそも、親のkindが存在しなければAncestorQueryは利用できないので、事前に考える必要がある。

3.別kindでユニークを担保する

「keyが int64 で自動採番である」という前提条件で
name が kind 全体でユニークだることを担保したい場合は、
name を key にした別のkindを用意して、
その kind でユニークを担保する必要がある。
http://stackoverflow.com/questions/11335651/how-to-handle-an-entity-with-two-unique-properties


ということで、
DataStoreではユニークな値をキーにするのが基本になるし、
トランザクション内でエンティティを取得するには
AncestorQuery or Get() or GetMult() しか利用できない
というお話でした。