如何在 App Engine 中表示一对一的关系

Posted

技术标签:

【中文标题】如何在 App Engine 中表示一对一的关系【英文标题】:How to represent one-to-one relationship in App Engine 【发布时间】:2011-06-07 16:22:17 【问题描述】:

假设您有一个“用户”记录的概念,希望将其存储在数据存储中。

class User (db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  created = db.DateTimeProperty(auto_now_add=True)
  twitter_oauth_token = db.StringProperty()
  twitter_oauth_secret = db.StringProperty()

您几乎每次使用用户对象时都想使用一些字段,例如 first_name 和 last_name。

但是,有些字段只有一个用例,例如 twitter_oauth_token 和 twitter_oauth_secret,而且当 95% 的时间不需要它们时,对它们进行序列化和反序列化有点效率低下。

因此,如果您将模型拆分:

class User (db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  created = db.DateTimeProperty(auto_now_add=True)

class UserTwitterOauth(db.Model):
  oauth_token = db.StringProperty(required=True)
  oauth_secret = db.StringProperty(required=True)
  created = db.DateTimeProperty(auto_now_add=True)

您可以在 UserTwitterOauth 中为用户放置一个 ReferenceProperty,但这实际上是一对多的,因为每个用户都有多个 UserTwitterOauth 对象并没有什么限制。您希望最多有一个与任何用户相关的 UserTwitterOauth。您如何将这些模型一对一地关联起来?

【问题讨论】:

顺便说一句:不要仅仅因为你认为它会更有效率就拆分你的模型。从长远来看,将其全部保存在一个实体上会更有效率,从而节省多次昂贵的 api 调用,尤其是在您发布的示例中。当你的用户模型上有数百个属性时,回来问这个问题,然后才能提高 write 性能 ;-) @Chris:本质上,这个问题可能与过早优化有关。但我个人喜欢将用户工件与其潜在连接分开的想法。如果您想对除了 twitter 连接之外的linkedin 连接进行建模...等等。 @jon,与 GAE 合作的很大一部分人往往是想办法de-规范化您的数据模型,以便您轻松查询它们并减少 API 调用,对于这种特殊情况,即使有 20 个不同的连接,它似乎也没有必要。 所以您设置的通常是更少的 api 调用而不是更小的 api 调用? @ʞɔıu 作为概括,是的,但这在很大程度上取决于实体的大小和它具有的属性数量。截止值远高于您在此处处理的几个额外属性。附言虽然您的用户名很有趣,但很难在回复中引用您。 【参考方案1】:

在这种特定情况下,您最好的选择可能是使 UserTwitterOauth 实体成为具有众所周知的键名的 User 实体的子实体,如下所示:

my_user = User(first_name="John", last_name="Smith")
my_user.put()
extra_info = UserTwitterOauth(parent=my_user, key_name="UserTwitterOauth")
extra_info.put()

您可以向User 类添加一个简单的方法或属性,以便于检索附加信息,并为UserTwitterOauth 添加一个类方法作为工厂方法,保留约定。

顺便提一下,User 是一个危险的实体名称 - 用户 API 也有一个名为 User 的类,除非您对导入非常小心,否则您最终可能会引用一个类打算参考对方。

【讨论】:

请注意,也许使用 db.put([my_user, extra_info]) 效率更高,不是吗? @sahid 只有在 User 实体使用键名时才有可能。【参考方案2】:

在我看来,从 twitter 访问令牌到用户的引用属性是迄今为止最容易维护的。确实,用户可以被许多访问令牌引用。

然而,在使用 GAE 时,您会发现自己很多时候都在按照惯例做事。

编辑防止多个访问令牌引用同一用户:

您可以通过User.usertwitteroauth_set 属性作为查询访问引用访问令牌。如果您想要一个更具描述性的名称,请在设置 ReferenceProperty 时指定参数collection_name。例如,假设您想在添加新的访问令牌之前删除任何引用访问令牌,您可以这样收集该逻辑:

class User(db.Model):
    def set_access_token(self, access_token):
        db.delete(self.twitter_access_tokens) # Think this should work, otherwise iterate over the query.
        new_access_token.user = self
        new_access_token.put()


class UserTwitterOauth(db.Model):
    user = db.ReferenceProperty(User, collection_name = 'twitter_access_tokens')

【讨论】:

我能以某种方式防止被骗者使用交易吗?

以上是关于如何在 App Engine 中表示一对一的关系的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 UML 在构造函数中表示 Java“this”关键字

hibernate的映射关系之一对多

Google App Engine 上 JPA​​ 中的简单一对多关系

如何在我的 Graphql Schema 中表示 Neo4j 关系属性?

如何在 ERD 中表示多对多关系

如何在Django Admin中表示这种两级深层关系?