aruuuuu
aruuuuu

Reputation: 1645

Why Should Hibernate Entities outside of a Session have equals() and hashcode() implemented?

Section 2.1.5 of the Hibernate user guide states that

In cases where you will be dealing with entities outside of a Session (whether they be transient or detached) ... you should consider implementing equals/hashCode.

Ignoring the obvious reason of using those entities in collections such as the Set, what are other situations that we would want or need to override the existing equals/hashcode as suggested in the hibernate doc?

Upvotes: 1

Views: 552

Answers (3)

v.ladynev
v.ladynev

Reputation: 19956

Looks like 2.1.5 is not a very clear section.

In cases where you will be dealing with entities outside of a Session (whether they be transient or detached) ... you should consider implementing equals/hashCode.

It doesn't mean "You have to override the equals() and hashCode() methods if you intend to use reattachment of detached instances".

It means other thing. If you get two objects with the same id from a session it will be the same object (in the memory).

Set<Person> set = new HashSet<Person>();
Session session = factory.openSession();

Person p1 = session.get( Person.class, 1 );
Person p2 = session.get( Person.class, 1);

set.put(p1);
set.put(p2);

session.close();

In the set will be one object because of p1 == p2 and Person uses default equals() and hashCode().

If you get two objects with the same id from a two sessions you will have two objects in the memory.

Set<Person> set = new HashSet<Person>();

Session session1 = factory.openSession();
Person p1 = session1.get( Person.class, 1 );
session1.close();

Session session2 = factory.openSession();
Person p2 = session1.get( Person.class, 1 );
session2.close();

set.put(p1);
set.put(p2);

In the set will be two objects because of p1 != p2.

Documentation in 2.1.5 just warns you, that if you want to use persistent objects outside a session with sets (or other such collections) you need to implement equals() and hashCode() or make other (!) efforts to have correct working collections.

Upvotes: 1

Naros
Naros

Reputation: 21133

First, entity equality is a domain detail which is best abstracted away from business code. The best place obviously for this is in the entity itself. Additionally, equality rules often vary based perhaps on entity state or other domain rules and so overriding the equals method insure those rules are adhered to not only in business code, but collection usage, and hibernate's session management.

Consider a composite-key based entity that uses several fields to consitute equality. Which of the following business code looks more appealing and is the least rigid to change:

public void someBusinessFunction(EntityA e1, EntityA e2) {
  if(e1.equals(e2))
    throw new SomeEqualityException();
  // do logic
}

public void someBusinessFunction2(EntityA e1, EntityA e2) {
  if(e1.getId().getFieldA().equals(e2.getId().getFieldA()) &&
       e1.getId().getFieldB().equals(e2.getId().getFieldB()) &&
       e1.getId().getFieldC().equals(e2.getId().getFieldC())) {
    throw new SomeEqualityException();
  }
  // do logic
}

From a business code perspective, we should not care what constitutes equality. All that code cares about is whether 2 instances of the same class equal one another. What rule is used to determine that use case is irrelevant.

In short, it's just good programming by abstracting details that should be abstracted in the first place.

EDIT

More specific to the Java language itself, the Object's stock equality only compares whether the two operands point to the same physical instance via the == operator. This is only valid if the two instances point to the same memory location.

It is possible to obtain the same domain entity via multiple transactions and therefore would point to two different memory locations because they were once managed by different sessions. In this case, the default equals method would return false which may not be desired.

By overriding the equals method, you can explicitly make sure that the above case always returns true for equality regardless of how the instance was obtained and where it may be stored in memory.

Additionally, the java doc explicitly states that overriding hashCode should occur when you override equals to maintain the contract between hashCode and equals so that when object equality is true, the hash codes are also equal as well.

Upvotes: 1

Dragan Bozanovic
Dragan Bozanovic

Reputation: 23562

If you currently don't use your detached entities in a Set (or in a Collection in general, think of remove(Object) and similar methods that rely on equals method), that does not mean that you (or your colleague) will not put those entities in a collection after six months when you've forgotten that equals is broken. That's good reason for me.

Upvotes: 0

Related Questions