App Engine:您会如何...对实体进行快照
假设您有两种消息和联系人,它们通过 消息上键的 db.ListProperty。用户创建一条消息,添加 一些联系人作为收件人,并通过电子邮件发送消息。后来,用户 删除作为接收者的联系人实体之一 信息。我们的应用程序应该删除相应的联系人 实体,但我们希望保留原始收件人列表 为用户记录而发送的消息。本质上,我们想要一个 消息实体发送时的快照。如果我们天真地 但是,删除联系人实体,我们会失去快照完整性;如果不, 我们留下了一把无效的钥匙。
遇到这种情况你会怎么处理 控制器逻辑或模型更改?
class User(db.Model):
email = db.EmailProperty(required=True)
class Contact(db.Model):
email = db.EmailProperty(required=True)
user = db.ReferenceProperty(User, collection_name='contacts')
class Message(db.Model):
recipients = db.ListProperty(db.Key) # contacts
sender = db.ReferenceProperty(User, collection_name='messages')
body = db.TextProperty()
is_emailed = db.BooleanProperty(default=False)
Let's say you have two kinds, Message and Contact, related by a
db.ListProperty of keys on Message. A user creates a message, adds
some contacts as recipients, and emails the message. Later, the user
deletes one of the contact entities that was a recipient of the
message. Our application should delete the appropriate Contact
entity, but we want to preserve the original recipient list for the
message that was sent for the user's records. In essence, we want a
snapshot of the message entity at the time it was sent. If we naively
delete the contact entity, though, we lose snapshot integrity; if not,
we are left with an invalid key.
How would you handle this situation,
either in controller logic or model changes?
class User(db.Model):
email = db.EmailProperty(required=True)
class Contact(db.Model):
email = db.EmailProperty(required=True)
user = db.ReferenceProperty(User, collection_name='contacts')
class Message(db.Model):
recipients = db.ListProperty(db.Key) # contacts
sender = db.ReferenceProperty(User, collection_name='messages')
body = db.TextProperty()
is_emailed = db.BooleanProperty(default=False)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会向联系人模型添加一个“已删除”布尔字段(或者更简洁的内容,例如删除的日期和时间),以便联系人永远不会被物理删除,而只会在设置该字段时“逻辑”删除。 (如果您愿意,这还可以让您提供其他很酷的功能,例如“显示我已删除的旧联系人”、“取消删除”功能等)。
这是所有需要维护历史完整性(和/或类似要求,例如“可审核性”)的存储系统中的常见方法。
如果逻辑上删除的实体数量巨大,可能会损害系统性能,经典的替代方案是拥有一个单独的、相同的模型“DeletedContacts”,但外键约束需要更多工作,例如 Message 类必须同时具有 < code>recipients 和
deleted_recipients
字段如果您需要外键完整性(但仅使用键,正如您所做的那样,不需要这项额外的工作) 。我怀疑普通用户会删除如此大比例的联系人,以保证上一段中解释的优化,所以在这种情况下,我会使用简单的“已删除”字段。
I would add a boolean field "deleted" (or something spiffier, such as the date and time of deletion) to the Contact model -- so that contacts are never physically deleted, but rather only "logically" deleted when that field is set. (This also lets you offer other cool features such as "show my old now-deleted contacts", "undelete" functionality, etc, if you wish).
This is a common approach in all storage systems that are required to maintain historical integrity (and/or similar requirements such as "auditability").
In cases where the sheer amount of logically deleted entities is threatening to damage system performance, the classic alternative is to have a separate, identical model "DeletedContacts", but foreign key constraints require more work, e.g. the Message class would have to have both
recipients
anddeleted_recipients
fiels if you needed foreign key integrity (but using just keys, as you're doing, this extra work would not be needed).I doubt the average user will delete such a huge percentage of their contacts as to warrant the optimization explained in the last paragraph, so in this case I'd go with the simple "deleted" field.
或者,您可以通过将电子邮件地址移至键名称并将用户设置为父实体来重构您的联系人模型。您的收件人属性将更改为原始电子邮件地址的字符串列表。这将为您提供电子邮件收件人的静态列表,而无需为每个收件人获取一组相应的实体,或要求此类实体仍然存在。如果您想获取联系人实体,您可以轻松地从用户和收件人地址构造它们的密钥。
这里的一个限制是现有联系人实体上的电子邮件地址无法更改,但我认为您无论如何都会遇到这个问题。使用现有模型更改联系地址会追溯更改已发送消息的收件人,我们知道这是一个问题。
Alternately, you could refactor your Contact model by moving the email address into the key name and setting the user as the parent entity. Your recipients property would change to a string list of raw email addresses. This gives you a static list of email recipients without having to fetch a set of corresponding entities for each one, or requiring that such entities still exist. If you want to fetch the contact entities, you can easily construct their keys from the user and the recipient address.
One limitation here is that the email address on an existing contact entity cannot be changed, but I think you have that problem anyway. Changing a contact address with your existing model would retroactively change the recipients of a sent message, which we know is a problem.