在Google App Engine中建模多对多关系数据
我在应用程序中有两个模型,分别是交易(Transaction)和人(Person),它们之间是多对多的关系。每个交易中都有一些人参与。对于每个人来说,还需要记录与他们相关的每个交易的金额。因此,我需要建立一个包含关系数据的多对多关系。谷歌建议使用以下方法:
http://code.google.com/intl/sv-SE/appengine/articles/modeling.html
使用这种方法,我的模型看起来是这样的:
class TransactionPerson(db.Model):
# References
transaction = db.ReferenceProperty(Transaction, required=True)
person = db.ReferenceProperty(Person, required=True)
# Values
amount = db.FloatProperty(required=True)
但是我发现这种方法在性能上很糟糕,因为如果我想要总结每个人在所有交易中的金额,我就需要循环遍历每个人、每个交易和交易与人之间的关系,这样才能实现“连接”并计算金额。
我的想法
我的想法是在交易模型中有两个列表:
class Transaction(db.Model):
persons = ListProperty(db.Key)
persons_amount = ListProperty(float)
这样,我就不需要为每个人遍历所有的交易与人之间的关系来找到相关的交易。而且我仍然可以根据某个人查询交易。
问题
- 这样做可行吗?在存储和检索时,列表的顺序是否总是相同,以确保索引在列表之间同步?
- 这样实现多对多关系和相关数据是否是个好方法?
2 个回答
1
1. 是的,你可以相信顺序会被保持。根据文档的说明:
当通过查询和get()方法获取实体时,列表属性的值会保持和存储时一样的顺序。唯一的例外是:Blob和Text类型的值会被移动到列表的最后面;不过,它们之间的原始顺序还是会保持不变。
2. 是的,ListProperties可以帮助你处理非规范化的关系。我经常会重复数据,并且像使用“缓存”一样利用列表属性来存储这些非规范化的数据。
2
我觉得你可能在解决错误的问题。使用中间关联实体是个不错的方法。不过你现在遇到的问题是,计算总结数据需要很长时间;你应该更关注这个问题。
更好的方法是提前计算总结数据。
以“每个人的交易总额”为例,这意味着你需要在“人”这个模型里加一个额外的字段,用来记录他们所有交易的累计总额。每当“交易人”被修改时,你都要更新这个字段,这样总结的数值才能始终保持正确。