1

假设您有两种类型,Message 和 Contact,由 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)

4

2 回答 2

2

我会在 Contact 模型中添加一个布尔字段“deleted”(或者更有趣的东西,例如删除的日期和时间)——这样联系人就不会被物理删除,而只会在设置该字段时“逻辑地”删除。(如果您愿意,这还可以让您提供其他很酷的功能,例如“显示我现在删除的旧联系人”、“取消删除”功能等)。

这是所有需要保持历史完整性(和/或类似要求,例如“可审计性”)的存储系统中的常用方法。

如果逻辑上删除的实体的绝对数量威胁到系统性能,经典的替代方案是拥有一个单独的、相同的模型“DeletedContacts”,但外键约束需要更多的工作,例如 Message 类必须同时具有recipientsdeleted_recipients如果您需要外键完整性(但只使用键,就像您正在做的那样,不需要这些额外的工作)。

我怀疑普通用户会删除如此大比例的联系人以保证上一段中解释的优化,所以在这种情况下,我会使用简单的“已删除”字段。

于 2010-06-11T04:52:10.970 回答
0

或者,您可以通过将电子邮件地址移动到键名并将用户设置为父实体来重构您的联系人模型。您的收件人属性将更改为原始电子邮件地址的字符串列表。这为您提供了电子邮件收件人的静态列表,而不必为每个人获取一组相应的实体,或者要求这些实体仍然存在。如果要获取联系人实体,可以轻松地从用户和收件人地址构造它们的密钥。

这里的一个限制是无法更改现有联系人实体上的电子邮件地址,但我认为无论如何您都会遇到这个问题。使用现有模型更改联系地址会追溯更改已发送消息的收件人,我们知道这是一个问题。

于 2010-06-11T14:37:25.967 回答