7

I find a lot of posts where it is explained that one should always override Equals/GetHashCode on a NHibernate entity class. If I don't use Sets, is this really necessary?

I simply can't find a sample where it is shown that missing Equals/GetHashCode can lead to unexpected and wrong behaviour. Everything seems to work perfectly without them. This is really strange that everyone says this is necessary but no one can provide a sample which shows why this is needed .

Antineutrino
  • 1,093
  • 3
  • 10
  • 26

2 Answers2

11

There was a question on SO recently about NHibernate doing select N+1 even if fetch is specified. The problem was with missing Equals / GetHashCode implementation.

The answer links to another similar question.

Here's another question on reasoning behind Equals / GetHashCode overrides.

Nhibernate n+1 with ternary relationship. Want the middle entity in the ternary
Nhibernate producing proxy despite HQL fetch
NHibernate: Reasons for overriding Equals and GetHashCode
Why Equals and GetHashCode are so important to NHibernate
Why is it important to override GetHashCode when Equals method is overridden?


Edit

You don't need to override them all the time. It may be necessary if you are using composite keys, multiple sessions with detached entities or stateless sessions.

If you are working with a single session only, NHibernate stores the entities to first level cache using an identity map. Entity comparison in that case is done by comparing ids.

In cases above (detached entity, stateless session), NHibernate compares actual entities, not their ids. By default, Object.Equals does reference equality. So two objects are equal if they point to the exact same instance. You might have two instances with the same identity, but Object.Equals would return false for them. This is in contrast with the Entity definition:

An object that is not defined by its attributes, but rather by a thread of continuity and its identity.

JBoss Hibernate wiki has a good explanation on Equals and HashCode with few code examples.

Community
  • 1
  • 1
Miroslav Popovic
  • 12,100
  • 2
  • 35
  • 47
  • This only seems to be related to composite keys. We do not use them. So this is the only case Equals/GetHashCOde is needed? I know the last three links you linked. I don't see there any code samples that reproduce wrong behaviour. – Antineutrino Jul 12 '12 at 09:28
  • Composite IDs are one case. I have updated my answer with some text and a link to Hibernate's wiki page... – Miroslav Popovic Jul 12 '12 at 10:39
  • -1 Comparing against a proxy and real object [will cause problems](http://stackoverflow.com/a/5857854/200322). Reference equality is *always* used unless you override `Equals`. You should **always** override `Equals`/`GetHashCode` and use identity comparison. – TheCloudlessSky Nov 21 '13 at 00:38
4

In fact, there are only rare cases when it leads to side effects. But if you get them, they are quite subtle. Apart from composite primary keys and dictionary keys, which always require a correct Equals / GetHashCode implementation.

NH cares about instantiating an entity only once in memory, so the default reference comparison should work ... if there wouldn't be lazy loading.

When not overriding Equals, you get problems when dealing with proxies. There are always two instances: the proxy and the real entity. They both represent the same entity. Only with a correctly implemented Equals method it is treated as the same.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • OK, so this means if I don't use composite keys or dictionaries the only reason is to make the use of an entity and its proxy transparent. – Antineutrino Jul 13 '12 at 08:37
  • The only reason I know about. We didn't implement Equals / GetHashCode in our project and didn't experience any problems until we started to use lazy loading. – Stefan Steinegger Jul 13 '12 at 10:10
  • I've added an example to [this post](http://stackoverflow.com/a/5857854/200322) that shows how equality could fail quite simply. If you have an object that is compared against a lazy-loaded collection, you will run into comparing a proxy with the real entity (and default reference equality would fail!). IMO, there shouldn't be "do it only in these edge cases", you should always do it to save your sanity when debugging these problems. – TheCloudlessSky Nov 21 '13 at 00:34