假设您有两种类型,即消息和联系人,与...相关 Message上的键的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)
答案 0 :(得分:2)
我会将一个布尔字段“删除”(或更糟糕的东西,例如删除的日期和时间)添加到联系人模型中 - 这样联系人永远不会被物理删除,而只会在该字段中“逻辑”删除已设定。 (如果您愿意,这也可以让您提供其他很酷的功能,例如“显示我现在删除的旧联系人”,“取消删除”功能等。)
这是维护历史完整性(和/或类似要求,如“可审计性”)所需的所有存储系统中的常用方法。
如果大量逻辑删除的实体有可能损害系统性能,那么经典的替代方案是使用单独的相同模型“DeletedContacts”,但外键约束需要更多工作,例如: Message类必须同时具有recipients
和deleted_recipients
fiels 如果你需要外键完整性(但是只使用键,正如你所做的那样,这个额外的工作不会需要)。
我怀疑普通用户会删除如此大比例的联系人,以保证最后一段中解释的优化,所以在这种情况下我会选择简单的“已删除”字段。
答案 1 :(得分:0)
或者,您可以通过将电子邮件地址移动到密钥名称并将用户设置为父实体来重构您的Contact模型。您的收件人属性将更改为原始电子邮件地址的字符串列表。这为您提供了电子邮件收件人的静态列表,而无需为每个收件人获取一组相应的实体,或者要求此类实体仍然存在。如果要获取联系人实体,可以从用户和收件人地址轻松构建其密钥。
这里的一个限制是现有联系人实体的电子邮件地址无法更改,但我认为您还有这个问题。使用现有模型更改联系地址将追溯更改已发送邮件的收件人,我们知道这是一个问题。