在阅读了GAE数据存储区API之后,我仍然不确定是否需要将键名和父项复制为实体的属性。
假设有两种实体:员工和分部。每位员工都有一个部门作为父级,并由帐户名称标识。我将帐户名称用作员工的密钥名称。但是在为Employee建模时,我仍然将这两个作为属性保存:
division = db.ReferenceProperty(Division)
account_name = db.StringProperty()
显然,我必须手动保持division
与其父级一致,account_name
与其密钥名称一致。我正在做这项额外工作的原因是:
但这实际上是不必要的工作,浪费时间和存储空间。我无法摆脱SQL思维 - 为什么Google不让我们将属性定义为关键?而另一个是父母?然后我们可以将它们命名并用作普通属性......
这里的最佳做法是什么?
答案 0 :(得分:5)
请记住,在GAE数据存储区中,您永远不能在创建实体后更改实体的父级或key_name。这些值对于实体的生命是永久性的。
如果Employee的account_name可能更改的可能性很小,那么您不能将其用作key_name。如果它永远不会改变,那么它可能是一个非常好的key_name,并允许您使用Employee.get_by_key_name()代替昂贵的查询为Employees做便宜的获取。
父级并不等同于外键。与外键相比更好的是引用属性。
使用父级的主要原因是父实体和子实体位于同一实体组中,允许您在单个事务中对它们进行操作。如果您只需要从Employee引用除法,那么只需使用引用属性。我建议熟悉实体组的工作方式,因为这对GAE数据建模非常重要:
使用parent也会导致写入性能问题,因为写入单个实体组的速度有限(大约每秒写入一次)。在决定是使用父属性还是引用属性时,您需要考虑在同一事务中需要修改哪些实体。在许多情况下,您可以使用Cross Group(XG)事务。这就是你要做出哪些权衡取舍。
所以我的建议是:
答案 1 :(得分:3)
当您使用Divison作为父级创建新的Employee对象时,它将类似于:
div = Division()
... #Complete the division properties
div.put()
emp = Employee(key_name=<account_name>, parent=div)
... #Complete the employee properties
emp.put()
然后,当您想要获得对该部门的引用时,员工是以下人员的一部分:
div = emp.parent()
#Get the Employee account_name (which is the employees's key name):
account_name = emp.key().name()
您不必将一个RefrenceProperty存储到一个Employee所属的部门,因为它已经在父级中完成了。此外,您可以根据需要从Employee实体的密钥中获取account_name。
查询密钥:
emp = Employee.get_by_key_name(<account_name>, parent=<division>)
#OR
div = Division.get_by_key_name(<keyname>)
#Get all employees in a division
emps = Employee.all().ancestor(div)