我在VoyageMongo上遇到问题。 编辑时,我会得到重复的对象(即更改和保存已保留的对象),特别是那些覆盖#=
和#hash
的对象。
这是(简化的)情况:我有UserAccount
类,实例实例为email
,salt
(用于密码加密)和name
。这些是#=
和#hash
方法:
= anObject
(self isKindOf: anObject class)
ifFalse: [ ^ false ].
^ self email = anObject email and: [ self salt = anObject salt ]
hash
^ (self salt hash + self email hash) hash
email
和salt
在创建时设置,并且永不更改。现在,这是一个小脚本:
UserAccount removeAll.
20 timesRepeat: [ UserAccount new save ].
10 timesRepeat: [ UserAccount selectAll atRandom
name: 'Joe Doe';
save ].
UserAccount selectAll size = 20
这将生成20个UserAccount
(在这种情况下,#new
创建一个包含随机电子邮件和盐的实例),然后随机选择10个并编辑其名称。 UserAccount selectAll
的最终大小应该保持为20,但通常更大,这意味着它存储重复项。
可能的罪魁祸首:有时无法对VOCache
进行调试,而WeakKeyDictionary
保留了缓存的对象(在reversedObjects
var中,对象本身是键)随着键数组变大,#scanFor:
开始注视不同的点(更具体地说,#startIndexFor:
),从而“命中”现有对象。发生这种情况时,我可以看到VOCache
的{{1}}中的对象,但是reversedObjects
找不到它。
长话短说:
VOCache>>keyAtValue:
?或者... #=
实施得不好吗?或者,当然,还有其他我没有看到的问题:)
非常感谢!
PS:使用最新的VoyageMongo在Pharo 6.1和7中对此进行了测试。
答案 0 :(得分:1)
作为一般规则,您不应覆盖实体对象中的#=和#hash,因为它们需要基于标识还是基于值。
如果2个对象的参数值匹配,则并不一定意味着它们表示相同的实体;如果您确实需要覆盖#=,那么您将需要一个业务密钥。 从数据库中提取实体对象时,最好不要覆盖它们,而仅使用基于标识的实体对象。即就像您正在使用OO DB一样。
也许这是一个航行错误,因为 reversedObjects 变量应该是WeakIdentityKeyDictionary吗?