我不断发现使用像db4o这样的对象数据库非常困惑的一件事是你应该如何处理通常由SQL / PL-SQL处理的复杂迁移。
例如,假设您在关系数据库中有一个名为my_users的表。最初您有一个名为“full_name”的列,现在您的软件在V2中,您希望删除此列,将全名拆分为空白区域,并将第一部分放在名为“first_name”的列中,将第二部分放在列中名为last_name。在SQL中,我只需填充“first_name”和“second_name”列,然后删除名为“full_name”的原始列。
我如何在db4o之类的内容中执行此操作?我是否编写了一个Java程序,脚本查找User.class的所有对象,在设置first_name和last_name时将full_name设置为null?当我执行下一个svn提交时,将没有与full_name对应的字段/ bean属性,这是一个问题吗?似乎在我的“架构”更改的生产应用程序中使用它我想编写一个脚本将数据从版本x迁移到版本x + 1然后在版本x + 2中实际删除我想要的属性摆脱版本x + 1,因为我无法编写Java脚本来修改不再属于我的类型的属性。
似乎问题的一部分是RDBMS基于一个简单的不区分大小写的基于字符串的名称来解析你所指的对象,在像Java这样的语言中输入比这更复杂,你不能引用属性如果getter / setter / field不是运行时加载的类的成员,那么你基本上需要在同一个脚本中有两个版本的代码(嗯,自定义类加载器听起来很痛苦),拥有你的类的新版本存储属于另一个包(声音凌乱),或使用我提到的版本x + 1 x + 2策略(需要更多的计划)。也许我从未从db4o文档中找到一些明显的解决方案。
有什么想法吗?希望这是有道理的。
答案 0 :(得分:10)
首先,db4o处理'简单'scenarios like adding or removing a field automatically。添加字段时,所有现有对象都存储了默认值。删除字段时,现有对象的数据仍在数据库中,您仍然可以访问它。重命名字段等是special 'refactoring'-calls。
现在你的场景你会做这样的事情:
我们假设我们有一个'地址'类。 'full_name'字段已被删除。现在我们不想把它复制到'firstname'和'surname'。然后就可以这样(Java):
ObjectSet<Address> addresses = db.query(Address.class);
StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class);
for (Address address : addresses) {
String fullName = (String)metaInfoOfField.get(address);
String[] splitName = fullName.split(" ");
address.setFirstname(splitName[0]);
address.setSurname(splitName[1]);
db.store(address);
}
正如您所建议的那样,您将为每个版本碰撞编写迁移代码。它不再是你班级的一部分,你必须使用上面的'StoredField'-API访问它。
您可以使用ObjectContainer.ext().storedClasses()
获取所有“已存储”类的列表。使用StoredClass.getStoredFields()
,您可以获得所有商店字段的列表,在您的班级中不再存在该字段。如果某个类不再存在,您仍然可以通过“GenericObject”类获取对象并访问它。
更新:适用于需要通过多个版本步骤迁移数据库的复杂方案。
例如,在版本v3中,address-object看起来完全不同。所以v1到v2的'migration-script'不再需要它所需的字段(在我的例子中是firstname和surename)。我认为处理这个问题有多种可能性。
答案 1 :(得分:2)
我在这里采取了一些疯狂的镜头,因为我没有在我的生活中重构过多的数据。
你做了一个奇怪的比较:如果你想“热迁移”数据库,你可能不得不做你所描述的x+1
,x+2
版本控制方法,但我不喜欢我真的知道 - 因为我不是数据库专家,所以我不知道如何使用SQL。
但是,如果要迁移“冷”,则可以通过从旧数据实例化新对象,存储新对象,删除商店中每个对象的旧对象,一步完成。请参阅db4o reference。
但老实说:RDBMS中的相同过程也很复杂,因为您必须取消激活约束检查(以及可能的触发器等)才能实际执行操作 - 可能不是在您提供的示例中,但是对于大多数现实世界的案例。毕竟,字符串拆分非常简单,几乎没有收获。
在SQL中,我只需填充“first_name”和“second_name”列
是的,使用简单的字符串拆分操作,您可以简单地这样做。但是在典型的重构场景中,您基于大量复杂的规则集重构对象,这些规则可能不容易在SQL中表达,可能需要复杂的计算或外部数据源。
要做到这一点,你也必须编写代码。
毕竟,我认为这两个过程没有太大区别。您将始终必须小心实时数据,并且您肯定会在两种情况下都进行备份。重构很有趣,但持久性很棘手,因此在任何情况下同步它都是一个挑战。