Reputation: 146
I'm having an issue with VoyageMongo. I'm getting duplicated objects when editing them (i.e. altering and saving already persisted objects), specifically with those that override #=
and #hash
.
Here's the (simplified) case: I have the UserAccount
class, with instance vars email
, salt
(for password encryption) and name
. These are the #=
and #hash
methods:
= 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
and salt
are set at creation and never change. Now, here's a little script:
UserAccount removeAll.
20 timesRepeat: [ UserAccount new save ].
10 timesRepeat: [ UserAccount selectAll atRandom
name: 'Joe Doe';
save ].
UserAccount selectAll size = 20
This generates 20 UserAccount
s (#new
creates an instance with random email and salt in this case), then picks 10 at random and edits their names. The final size of UserAccount selectAll
should stay at 20, but it is usually larger, meaning it's storing duplicates.
Possible culprit: debugging into VOCache
, the WeakKeyDictionary
holding the cached objects (in reversedObjects
var, where objects themselves are the keys) sometimes fails to "hit" existing object, since the #scanFor:
starts looking at different points (more specifically, #startIndexFor:
) as the keys array grows larger. When this happens, I can see the object inside VOCache
's reversedObjects
but VOCache>>keyAtValue:
fails to find it.
Long story short:
#=
in persistent objects? Or...#hash
is not well implemented?Or, of course, any other issue I'm not seeing :)
Thanks a lot!
PS: tested this in Pharo 6.1 and 7 with latest VoyageMongo.
Upvotes: 2
Views: 93
Reputation: 176
As a general rule you shouldn't override the #= and #hash in entity objects as these need to be based on identity vs on value.
If 2 objects match on the values of their parameters then this does not necessarily mean they represent the same entity; if you really need to override the #= then you will need a business key. Best to simply not override and just use entity objects based on identity when you pull them from the DB. i.e. as if you're working with an OO DB.
Perhaps this is a Voyage bug as the reversedObjects variable should be a WeakIdentityKeyDictionary?
Upvotes: 1