2008年5月20日火曜日

Google App Engine Datastoreメモ

HasManyの関係があった場合

 class MyModel1(db.Model):
   text = db.StringProperty()
 class MyModel2(db.Model)
   text = db.StringProperty()
   myModel1 = db.ReferenceProperty(MyModel1)
 myModel1 = MyModel1.get_by_id(1)
 myModel2s = MyModel1.mymodel2_set
みたいなカンジで「保持するmodel名の小文字+"_set"」でぶらさがるEntityのリストを取得できる。この名称はReferencePropertyのコンストラクタのcollection_name引数で指定する事もできる。

Transaction中にクエリを発行できない制限について

Transaction中でクエリが使えないと、更新対象に対して関連のあるEntityを芋づるで削除したいときに困るかも。そんな時はModel.get_by_id()を使って更新対象を取得すれば良い。例えば以下のような例。
 class MyModel1(db.Model):
  title = StringProperty()
 class MyModel2(db.Model):
  ref = ReferenceProperty(MyModel1)
  otherRef = ReferenceProperty(OtherModel)
 
 def method():
   model1 = MyModel1.get_by_id(int(idString))
   model2s = MyModel2.gql("WHERE ref = :ref", ref=model1)
   db.run_in_transaction(delete_cascade, model1, model2s)
 
 def delete_cascade(model1, model2s)
  db.delete(model2s)
  model1.delete()
一見すると、run_in_transaction()の中ではクエリは無いように見えるが"db.delete(model2s)"実行時に内部的に"WHERE ref=:ref"のクエリが走るため、そこで"BadRequestError: Can't query inside a transaction."となってしまう。ただし、クエリが使えないといってもGqlQuery系が使えない、という意味なので"Model.get_by_id()"を使う事は問題ないみたい。
 def method():
   model1 = MyModel1.get_by_id(int(idString))
   _model2s = MyModel2.gql("WHERE ref = :ref", ref=model1)
   model2Ids = []
   for m2 in _model2s:
     model2Ids.append(m2.key().id())
   model2s = MyModel2.get_by_id(ids=model2Ids)
   db.run_in_transaction(delete_cascade, model1, model2s)
idのリストを作って…というのが面倒だが、今のところこれしか方法がわからない。
コメントを投稿