【发布时间】:2012-01-30 21:09:30
【问题描述】:
我正在为我们当前的生产 App Engine 应用程序编写数据存储迁移。
我们对数据模型进行了一些相当广泛的更改,因此我正在尝试建立一个架构,以便将来更轻松地迁移。这包括迁移测试套件和迁移脚本的通用类结构。
我目前的策略遇到了问题。对于迁移和测试脚本,我需要一种方法将旧模式中的模型类和新数据模式的模型类同时加载到内存中,并使用其中任何一种加载实体。
这是一组示例模式。
rev1.py
class Account(db.Model):
_version = db.IntegerProperty(default = 1)
user = db.UserProperty(auto_current_user_add = True, required = True)
name = db.StringProperty()
contact_email = db.EmailProperty()
rev2.py
class Account(db.Model):
_version = db.IntegerProperty(default = 2)
auth_id = db.StringProperty()
name = db.StringProperty()
pwd_hash = db.StringProperty(required = True, indexed = False)
迁移脚本可能类似于:
import rev1
import rev2
class MyMigration(...):
def isNeeded(self):
num_accounts = num_entities_with_version(rev1.Account, 1)
return num_accounts > 0
def run(self):
rev1_accounts = rev1.Account.all()
for account in [a for a in rev1_accounts if account._version == 1]:
auth_id = account.contact_email
if auth_id is None or auth_id == '':
auth_id = account.user.email()
new_account = rev2.Account.create(auth_id = auth_id,
name = account.name)
测试套件看起来像这样:
import rev1
import rev2
class MyTest(...):
def testIt(self):
# Setup data
act1 = rev1.Account(name = '..', contact_email = '..')
act1.put()
act2 = rev1.Account(name = '..', contact_email = '..')
act2.put()
# Run migration
migration.run()
# Check results
accounts = rev2.Account.all().fetch(99)
如您所见,我以两种方式使用旧版本。我在迁移中使用它来读取旧格式的数据并将其转换为新格式。 (注意:由于所需的 pwd_hash 字段和其他字段更改等原因,我无法以新格式阅读它)。我在测试套件中使用它在运行迁移之前以旧格式设置测试数据。
这一切在理论上看起来都很好,但在实践中它就崩溃了,因为 GAE 不允许为同一种类型加载多个模型,或者更具体地说,查询只返回最近定义的模型。
在开发服务器中,这似乎是由于在查询实体(例如:Account.get(my_key))时调用 get() 的过程调用了一个结果挂钩,该挂钩通过以下方式构建结果模型对象从数据中调用实体种类名称的 class_for_kind。因此,即使我可以调用 rev2.Account.get(),它也可能会构建 rev1.Account 模型对象,因为类型 'Account' 映射到 _kind_map 字典中的 rev1.Account。
这让我重新考虑了我的迁移策略,我想问问是否有人有想法。具体来说:
- 在运行时在测试和生产服务器上手动覆盖 google.appengine.ext.db._kind_map 以允许此迁移方法工作是否安全?
- 有没有更好的方法可以同时在内存中保存模型的两个版本?
- 是否有其他迁移方法可能是完成这项工作的更明智的方法?
我想过尝试的其他方法包括:
- 版本更改时更改实体种类。 (使用 kind() 更改它)然后当我们迁移时,我们将所有类移动到新的种类名称。
- 找到一种方法来查询实体并取回尚未构建到完整对象中的“原始”对象(原型缓冲区??)。 (不适用于测试)
- “Just Do It Live”:不要为此编写测试,只需尝试使用最新架构进行迁移,加载旧数据以解决出现的问题。
【问题讨论】:
标签: google-app-engine google-cloud-datastore data-migration