2

我遇到了 VoyageMongo 的问题。我在编辑它们时得到了重复的对象(即更改和保存已经持久化的对象),特别是那些覆盖#=#hash.

这是(简化的)案例:我有一个UserAccount类,带有实例 vars emailsalt(用于密码加密)和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

这会生成 20UserAccount秒(#new在这种情况下创建一个带有随机电子邮件和盐的实例),然后随机选择 10 个并编辑它们的名称。的最终大小UserAccount selectAll 应该保持在 20,但它通常更大,这意味着它正在存储重复项。

可能的罪魁祸首:调试到VOCacheWeakKeyDictionary持有缓存对象(在reversedObjectsvar 中,对象本身是键)有时无法“命中”现有对象,因为随着键数组的增大#scanFor:,开始查看不同的点(更具体地说, )。#startIndexFor:发生这种情况时,我可以看到VOCache's内部的对象,reversedObjectsVOCache>>keyAtValue:找不到它。

长话短说:

  • 是不是我不应该#=在持久对象中覆盖?或者...
  • 是不是我#hash的执行不好?

或者,当然,我没有看到的任何其他问题:)

非常感谢!

PS:使用最新的 VoyageMongo 在 Pharo 6.1 和 7 中对此进行了测试。

4

1 回答 1

1

作为一般规则,您不应覆盖实体对象中的#= 和#hash,因为它们需要基于身份与值。

如果 2 个对象的参数值匹配,那么这并不一定意味着它们代表同一个实体;如果您真的需要覆盖 #= 那么您将需要一个业务密钥。当您从数据库中提取实体对象时,最好不要覆盖并仅使用基于身份的实体对象。即好像您正在使用OO DB。

也许这是一个 Voyage 错误,因为reversedObjects变量应该是 WeakIdentityKeyDictionary?

于 2019-01-14T05:40:32.967 回答