我应该使用ReferenceProperty预取还是复制引用实体的列?

时间:2013-04-26 07:47:27

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

我想了解如何将ReferenceProperty用于常见的使用场景 在典型的应用程序中,我们始终显示Referenced Entity的列。

例如,考虑采购订单应用程序。

class POCategory(db.Model):
    name = db.StringProperty()

class POSubCategory(db.Model):
    category = db.ReferenceProperty(POCategory, collection_name='sub_categories')
    name = db.StringProperty()

class PurchaseOrder(db.Model):
    total_amount = db.FloatProperty()

class PurchaseOrderLineItem(db.Model):
    category = db.ReferenceProperty(POCategory, collection_name='po_line_items')
    sub_category = db.ReferenceProperty(POSubCategory, collection_name = 'po_line_items')
    amount = db.FloatProperty()

这是我们通常在典型应用程序中显示的内容。

+---------------+---------------+--------+
|   Category    | Sub Category  | Amount |
+---------------+---------------+--------+
| Blue Category | Water         | $12.00 |
| Red Category  | Fire          | $20.00 |
+---------------+---------------+--------+
|          Purchase Order Total | $22.00 |
+---------------+---------------+--------+

我是否应该使用 ReferenceProperty Pre-fetching 来避免N + 1选择问题?

在我的采购订单行项目中复制类别和子类别名称,如下所示?

class PurchaseOrderLineItem(db.Model):
    category = db.ReferenceProperty(POCategory, collection_name='po_line_items')
    category_name = db.StringProperty()

    sub_category = db.ReferenceProperty(POSubCategory, collection_name = 'po_line_items')
    sub_category_name = db.StringProperty()

    amount = db.FloatProperty()

显然,类别和子类别的名称是可编辑的 因此,当有人更新name属性时,我将不得不查询并循环所有引用的PurchaseOrderLineItem实体并更新我的重复name属性。

    #----------------------------------------
    #             BAD DESIGN
    #----------------------------------------
    po_category.name = 'New Category Name'

    # build list of line items to be updated
    update_list = []
    for child_line_item in po_category.po_line_items:
        child_line_item.category_name = po_entity.name
        update_list.append(child_line_item)

    db.put(po_category, update_list)

我知道是一个很好的可扩展解决方案,因为随着时间的推移,我们会有很多行项目需要更新。 RDBMS的思维方式难以摆脱。

那么有人可以教我如何思考这些典型场景吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

正如您所说,由于您经常可以编辑类别名称,因此不应将其嵌入到行项目中。

而是使用NDB(自动缓存获取)和多次获取(一次数据库调用以获取多个实体)来获取类别和子类别。