The reccomendation of using the properties of an object rather then
the object identity and or synthetic primary key is just as broken as
the problem we are trying to highlight and solve. This is because if
any of the properties used in the composite key are edited all the
problems listed by the main author will occur. In some cases it could
be worse because the problems associated with changes to the
properties making up the new key will most likely only show up during
production.
The solution actually lies in hibernates contract of maintaining a
single instance per object in the session cache.
Equals is easy:
public boolean equals(Object other){
if( this == other)
return true;
if( (this.id == null) || (other.id== null))
return false;
return this.id.equals(other.id);
}
Here we assume that new objects are always different unless they are
the same object. If an object is loaded from the database it has a
valid id and therefore we can check against object ids.
Hash code is more difficult we need to ensure that if:
A==B
then
A.hashcode == B.hashcode
If we base it on Ids which dont change once assigned then we only have
to ensure that new objects also obey the above contract within the
scope of the session.
private Integer hashcodeValue = null;
public synchronized int hashCode(){
if( hashcodeValue == null){
if( id == null){
hashcodeValue = new Integer(super.hashcode());
} else {
hashcodeValue = generateHashCode(id);
}
}
return hashcodeValue.intValue();
}
What we are doing here is ensuring that once a hshcode value is used,
it never changes for this object. This allows us to use object
identity for new objects and not run into the problems listed above.
In fact the only case where this is a problem is when we save a new
object, keep it around after we close the session, load a new instance
of the object in a new session and then compare them.
in this case we get A==B but a.hashcode != b.hashcode
The above functions work in all other scenarios and don't lead to
broken implementations when the propety of the object are edited. The
whole point in generating synthetic primary keys in the first place is
to avoid having a primary key which is dependant on an object
property and which therefore may change during the life time of the
object. |