【问题标题】:Entity groups, ReferenceProperty or key as a string实体组、ReferenceProperty 或键作为字符串
【发布时间】:2011-03-24 21:14:44
【问题描述】:

在 gae 平台上构建了一些应用程序后,我通常在基本上每个应用程序中使用数据存储区中不同模型之间的某种关系。而且我经常发现自己需要查看同一父级的记录(例如将所有条目与同一父级匹配)

从一开始我就使用 db.ReferenceProperty 来建立我的关系,例如:

class Foo(db.Model):
    name = db.StringProperty()

class Bar(db.Model):
    name = db.StringProperty()
    parentFoo = db.ReferanceProperty(Foo)

fooKey = someFooKeyFromSomePlace
bars = Bar.all()
for bar in bar:
    if bar.parentFoo.key() == fooKey:
        // do stuff

但最近我已经放弃了这种方法,因为bar.parentFoo.key() 每次都会进行子查询来获取 Foo。我现在使用的方法是将每个Foo 键作为字符串存储在Bar.parentFoo 上,这样我就可以将其与someFooKeyFromSomePlace 进行字符串比较,并消除所有子查询开销。

现在我开始研究实体组,想知道这是否是更好的方法?我真的不知道如何使用它们。

至于上述两种方法,我想知道使用它们有什么缺点吗?可以使用存储的密钥字符串卷土重来并在 * * * 中咬我。最后但同样重要的是,有没有更快的方法来做到这一点?

【问题讨论】:

  • 你有什么理由不做Bar.all().filter("parentFoo =", fooKey) 还是仅仅因为你对这个问题的简化?
  • 只是为了这个问题:)

标签: python google-app-engine google-cloud-datastore


【解决方案1】:

提示:

替换...

bar.parentFoo.key() == fooKey

与...

Bar.parentFoo.get_value_for_datastore(bar) == fooKey

为了避免额外的查找,只需从 ReferenceProperty 获取密钥

Property Class

【讨论】:

  • 双重提示:如果您只使用键比较的值,请使用 KeyProperty 而不是 ReferenceProperty。 github.com/Arachnid/aetycoon/blob/master/__init__.py
  • 如何避免额外的查找?我的意思是get_value_for_datastore 听起来确实像是对数据库的查询。我可能弄错了。
  • get_value_for_datastore 只获取存储在ReferenceProperty 自身中的Key,因此不需要数据存储区RPC。同样,Calvin 的方法通过完全消除 ReferenceProperty 取消引用的 magicness 来避免查找,因此您可以在没有 bar.parentFoo 的纵容的情况下从数据存储中显式获取相关实体
【解决方案2】:

我认为您也应该考虑这一点。这将帮助您获取单个父项的所有子实体。 宝马=汽车(品牌=“宝马”) bmw.put()

lf = Wheel(parent=bmw,position="left_front")
lf.put()

lb = Wheel(parent=bmw,position="left_back")
lb.put()

bmwWheels = Wheel.all().ancestor(bmw)

更多建模参考。你可以参考这个Appengine Data modeling

【讨论】:

  • 很好,它会派上用场的。但不幸的是,我将所有Bar 与同一个父级配对到自己的列表中。所以这是一个检查它是否有 foo1 作为父它进入 foo1List 等等的问题。
【解决方案3】:

我不确定您要使用该示例代码块做什么,但我觉得可以通过以下方式完成:

bars = Bar.all().filter("parentFoo " = SomeFoo)

对于实体组,它们主要用于您想要更改事务中的多个内容,因为 appengine 将其限制为仅同一组内的实体;此外,appengine 允许祖先过滤器 (http://code.google.com/appengine/docs/python/datastore/queryclass.html#Query_ancestor),根据您需要做什么,这可能很有用。使用上面的代码,如果您将 Bar 的父级设置为 Foo,您也可以非常轻松地使用祖先查询。

如果您的目的仍然需要大量“子查询”,那么 Nick Johnson 在这里概述了一种简洁的预取模式:http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine 它基本上将您在实体集中需要的所有属性作为一个巨大的 get而不是一堆小的,这消除了很多开销。但是请注意他的警告,尤其是关于在使用此预取方法时更改实体的属性。

不是很具体,但这就是我可以给你的所有信息,直到你更具体地知道你在这里想要做什么。

【讨论】:

  • 感谢您的链接,它帮了很多忙。这个小问题我不确定如何更具体。我一直在寻找如何在一般意义上存储模型之间的关系的指针。以及不同方法的缺点。
【解决方案4】:

在设计模块时,您还需要考虑是否希望能够将其保存在事务中。但是,只有在您需要使用事务时才这样做。

另一种方法是像这样分配父级:

from google.appengine.ext import db

class Foo(db.Model):
    name = db.StringProperty()

class Bar(db.Model):
    name = db.StringProperty()

def _save_entities( foo_name, bar_name ):
    """Save the model data"""
    foo_item = Foo( name = foo_name )
    foo_item.put()    
    bar_item = Bar( parent = foo_item, name = bar_name )
    bar_item.put()

def main():
    # Run the save in a transaction, if any fail this should all roll back
    db.run_in_transaction( _save_transaction, "foo name", "bar name" )

    # to query the model data using the ancestor relationship
    for item in bar_item.gql("WHERE ANCESTOR IS :ancestor", ancestor = foo_item.key()).fetch(1000):
        # do stuff

【讨论】:

  • 使用run_in_transaction 而不是调用_save_transaction() 有什么好处?
  • 我已经更新了代码,使其更加清晰,_save_entities() 将尝试同时保存 Foo 和 Bar,但如果 Bar 方法无法保存,则保留一个孤立的 Foo 实体。在事务中运行时,如果任一保存失败,则两个保存都将回滚,并且不会向 Bigtable 提交任何内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 2019-03-02
  • 1970-01-01
相关资源
最近更新 更多