在Google App Engine(GAE)数据存储区中复制键名和父级作为属性?

时间:2012-09-07 14:09:46

标签: python google-app-engine google-cloud-datastore

在阅读了GAE数据存储区API之后,我仍然不确定是否需要将键名和父项复制为实体的属性。

假设有两种实体:员工和分部。每位员工都有一个部门作为父级,并由帐户名称标识。我将帐户名称用作员工的密钥名称。但是在为Employee建模时,我仍然将这两个作为属性保存:

division = db.ReferenceProperty(Division)
account_name = db.StringProperty()

显然,我必须手动保持division与其父级一致,account_name与其密钥名称一致。我正在做这项额外工作的原因是:

  1. 恐怕GQL / Datastore API可能不支持父级和密钥名称以及普通属性。有什么我可以做的关于一个属性但不是父或关键名称(或他们基本上是引用属性)?如何在GQL查询中使用密钥名称?
  2. 关键名称和父母的含义不是特别清楚。由于名称不是自我描述的,我必须告知其他贡献者我们使用帐户名作为关键名称......
  3. 但这实际上是不必要的工作,浪费时间和存储空间。我无法摆脱SQL思维 - 为什么Google不让我们将属性定义为关键?而另一个是父母?然后我们可以将它们命名并用作普通属性......

    这里的最佳做法是什么?

2 个答案:

答案 0 :(得分:5)

请记住,在GAE数据存储区中,您永远不能在创建实体后更改实体的父级或key_name。这些值对于实体的生命是永久性的。

如果Employee的account_name可能更改的可能性很小,那么您不能将其用作key_name。如果它永远不会改变,那么它可能是一个非常好的key_name,并允许您使用Employee.get_by_key_name()代替昂贵的查询为Employees做便宜的获取。

父级并不等同于外键。与外键相比更好的是引用属性。

使用父级的主要原因是父实体和子实体位于同一实体组中,允许您在单个事务中对它们进行操作。如果您只需要从Employee引用除法,那么只需使用引用属性。我建议熟悉实体组的工作方式,因为这对GAE数据建模非常重要:

使用parent也会导致写入性能问题,因为写入单个实体组的速度有限(大约每秒写入一次)。在决定是使用父属性还是引用属性时,您需要考虑在同一事务中需要修改哪些实体。在许多情况下,您可以使用Cross Group(XG)事务。这就是你要做出哪些权衡取舍。

所以我的建议是:

  • 如果员工的account_name绝对不会更改,请将其用作key_name。否则就把它变成一个基本属性。
  • 如果您需要在同一笔交易中修改员工和部门(并且您无法使其与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)