如何在 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”关键字
Google App Engine 上 JPA 中的简单一对多关系