4.3. Implementing equals() and hashCode()

intend to put instances of persistent classes in a Set
(the recommended way to represent many-valued associations)
and

intend to use reattachment of detached instances

Hibernate guarantees equivalence of persistent identity (database row) and Java identity
only inside a particular session scope. So as soon as we mix instances retrieved in
different sessions, we must implement equals() and
hashCode() if we wish to have meaningful semantics for
Sets.

The most obvious way is to implement equals()/hashCode()
by comparing the identifier value of both objects. If the value is the same, both must
be the same database row, they are therefore equal (if both are added to a Set,
we will only have one element in the Set). Unfortunately, we can't use that
approach with generated identifiers! Hibernate will only assign identifier values to objects
that are persistent, a newly created instance will not have any identifier value! Furthermore,
if an instance is unsaved and currently in a Set, saving it will assign
an identifier value to the object. If equals() and hashCode()
are based on the identifier value, the hash code would change, breaking the contract of the
Set. See the Hibernate website for a full discussion of this problem. Note
that this is not a Hibernate issue, but normal Java semantics of object identity and equality.

We recommend implementing equals() and hashCode()
using Business key equality. Business key equality means that the
equals() method compares only the properties that form the business
key, a key that would identify our instance in the real world (a
natural candidate key):