我有一个ZODB安装,我必须组织几百万个大约几种不同类型的对象。我有一个通用的容器类Table
,它包含BTrees,可以通过属性或这些属性的组合来索引对象。数据一致性非常重要,因此我想强制执行,当我写入索引所涵盖的任何属性时,索引会自动更新。所以一个简单的obj.a = x
应该足以计算所有新的依赖索引条目,检查是否有任何冲突,最后写下索引和值。
一般来说,我很乐意使用一个库,所以我看着repoze.catalog和IndexedCatalog,但对此并不满意。 IndexedCatalog似乎已经死了很长一段时间,并没有提供对象更改的一致性。 repoze.catalog似乎更常用,更活跃,但据我所知,也没有提供这种一致性。如果我在这里错过了一些东西,我很乐意听到它并且更喜欢重复使用重新发明。
所以,除了试图找到问题库之外我怎么看,我必须用描述符拦截对dataobject属性的写访问权,让Table
类做改变索引的魔力。为此,描述符实例必须知道,他们必须与哪些Table
实例进行通信。当前的实现类似于:
class DatabaseElement(Persistent):
name = Property(constant_parameters)
...
class Property(object):
...
def __set__(self, obj, name, val):
val = self.check_value(val)
setattr(obj, '_' + name, val)
生成这些DatabaseElement
类时,尚未创建数据库及其中的对象。正如本nice answer中所提到的,我可能不得不创建一些单例查找机制来查找Table
对象,而不将它们作为实例化参数传递给Property
。有更优雅的方式吗?坚持描述符本身?欢迎任何建议和最佳实践示例!
答案 0 :(得分:0)
所以我终于想通了自己。解决方案分为三个部分。不需要丑陋的单身人士。 Table
提供了检查冲突的逻辑,DatabaseElement
能够查找负责任的Table
而无需丑陋的变通办法,Property
注意,索引会在任何变更之前更新编写索引值。这里有一些片段,主要线索是DatabaseElement
的表格查找。我也没有看到任何记录。好的额外:它不仅验证对单个值的写入,我还可以一次性检查多个索引值的更改。
class Table(PersistentMapping):
....
def update_indices(self, inst, updated_values_dict):
changed_indices_keys = self._check_collision(inst, updated_values_dict)
original_keys = [inst.key(index) for index, tmp_key in changed_indices_keys]
for (index, tmp_key), key in zip(changed_indices_keys, original_keys):
self[index][tmp_key] = inst
try:
del self[index][key]
except KeyError:
pass
class DatabaseElement(Persistent):
....
@property
def _table(self):
return self._p_jar and self._p_jar.root()[self.__class__.__name__]
def _update_indices(self, update_dict, verify=True):
if verify:
update_dict = dict((key, getattr(type(self), key).verify(val))
for key, val in update_dict.items()
if key in self._key_properties)
if not update_dict:
return
table = self._table
table and table.update_indices(self, update_dict)
class Property(object):
....
def __set__(self, obj, val):
validated_val = self.validator(obj, self.name, val)
if self.indexed:
obj._update_indices({self.name: val}, verify=False)
setattr(obj, self.hidden_name, validated_val)