VoyageMongo:是否可以在持久化类中重写#=?

时间:2019-01-07 21:29:08

标签: smalltalk pharo

我在VoyageMongo上遇到问题。 编辑时,我会得到重复的对象(即更改和保存已保留的对象),特别是那些覆盖#=#hash的对象。

这是(简化的)情况:我有UserAccount类,实例实例为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

emailsalt在创建时设置,并且永不更改。现在,这是一个小脚本:

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中对此进行了测试。

1 个答案:

答案 0 :(得分:1)

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

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

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