You should not override them. It is wrong from a perspective of what an entity is supposed to be.
A hibernate-entity (an instance of an entity-class) is your programs representation of an entry in the database (A 'row', in the simplest case of a single SQL-table). This row exists outside of your program logic and memory. It is similar to an object representing a 'file' or a 'thread', it is not contained in your program, it is a proxy to something outside of your program. At what point does it make sense to say that two file-objects are the same? When they represent the same file. But how often do you even compare file-objects? You don't, because the same file should not have two different representations in the same context.
In this way - the hibernate-concept of an "Entity" matches the Domain-Driven-Design (DDD) concept of an entity, which is probably no accident. You can read up on it on SO: The meaning of "entity" in Domain-Driven Design DDD: what's the use of the difference between entities and value objects?
Hibernate aims to preserve the abstraction of the entity representing your row. Even if you read the same row from two queries in the same session, it will return the same object again. You can only get two different java-objects representing the same database-row if you detach/reattach or use multiple sessions. This is not a standard usecase of hibernate, but it is entirely possible this happens, for example when multithreading.
So imagine your program finds itself with these two objects:
Person(id=3, name='Sarah', occupation='programmer')
Person(id=3, name='Sarah', occupation='manager')
Which occupation should you continue with for Sarah? Is this an error? Does one version 'win'? You cannot decide just from these two rows, the context of what you are doing matters. And the context to decide this is not included in a HashMap or an entity-class, it is in the code where these two appear.
If you were to define some equality on Person
and throw these two objects into
the same HashSet
or whatever, then one of two things would happen:
'first-save wins' - one version of Sarah gets discarded based on ordering which is probably an implementation-detail of your code
You have two conflicting versions of Sarah in your datastructure.
Both are bad. Notice how it doesn't matter how the equality is defined, any general equality would lead to these results - the mistake is not the specific definition of the equality, the mistake is to leave disambiguation to a part of the code that does not have the right context to decide it.
Two approaches are given in the answers on this site:
Number 1 might actually work, but bear in mind that business-keys are often immutable in most but not all usecases - the classic example is a user (entity) changing their email-adress (business-key). And keep in mind this doesn't help you resolve ambiguity still, and having an equality that you shouldn't be using is not useful.
Number 2 completely defeats the purpose of hash-based datastructures. It is plain silly to do this. Your HashSets will decay into linked-lists. You are not hashing anything, so you can't have a hashset. Ii think a lot of people (myself included) do not notice this is happening because the code looks so careful and advanced (taking care of Proxies and whatnot)
If you feel the need to hash your entities, by using them as keys in a map or as elements in a set, consider these alternatives:
Use identity-based collections: IdentityHashMap
, IdentityHashSet
. They
determine equality with reference-equality (==
) not .equals()
Extract business-keys or IDs and use them as keys. Any Set<Person>
can be a
Map<PersonKey, Person>
, any Map<Person, Something>
can be a Map<PersonKey, Something>
.
Just use a List<Person>
, unlike sorting or hashing containers it does not limit mutability of its elements.
If you frequently store the same extra-information on your entities in a
Map<Person, Extra>
, make Extra
a transient field on Person
There is a very general problems at play here:
You cannot modify an object with respect to its hash-value while it is in a hash-based datastructure (a similar rule holds for sorting-based datastructures). Java, like many other languages, does not have any compiler-rules to help you here. You have to ensure this is true, otherwise your objects get 'lost'. No hibernate here.
Where hibernate comes into play is that it may assign an ID to your object when it saves it, so mutations may happen at places where a beginner may not expect them (though they still happen in a controlled manner).