3

After reading this article , im bending toward not overriding equals() and hashCode() altogether.

In the summary of that article, concerning the no eq/hC at all column, the only consequence is that i couldnt do the comparison operations like :

  1. contains() in a List for detached entities, or
  2. compare the same entities from different sessions

and expect the correct result.

But im still in doubt and would like to ask your experiences about this whether it is a bad practice to skip equals and hashCode altogether and what other consequences that i still dont know for now.

Just another point of information, im bending towards using List Collections over Set. And my assumption is that i dont really need to override hashCode and equal when storing in a List.

Bertie
  • 17,277
  • 45
  • 129
  • 182
  • 1
    This has been asked before: [Should I write equals() methods in JPA entities?](http://stackoverflow.com/questions/4388360/should-i-write-equals-methods-in-jpa-entities). My answer was: `hashCode()` and `equals()` should be implemented, but without using the `@Id` property. (Others had different opinions :-)) – Sean Patrick Floyd Mar 04 '11 at 08:52
  • hello ! yes, im aware of your previous post before posting mine because i did googling around for similar problems. the difference with my post is that you want to know whether that will work without defining equal(), where my question is more to the what will i lose without defining them. and to the good answer in your post, is more to the pros n cons of each way on how to define equals() and hashCode() – Bertie Mar 04 '11 at 09:01
  • There is a good summary here: http://burtbeckwith.com/blog/?p=53 – bert Mar 04 '11 at 09:03
  • 1
    If you do not want to override, then you can apply different custom collections/comparators whom sometimes look at the whole object, sometimes just at the primary key, after what suits your context. But this is not a free lunch either.. – ThomasRS Mar 04 '11 at 12:17

3 Answers3

3

whether it is a bad practice to skip equals and hashCode altogether

Yes. You should always override your equals and hashCode. Period. The reason is that this method is present already in your class, implemented in Object. Turns out that this implementation is generic, and nearly 100% of the times it's a wrong implementation for your own objects. So, by skipping equals/hashCode you are in fact providing a wrong implementation and will (in the best case scenario) confuse whoever uses these classes. It may be your colleagues, or it may be some framework you are using (which can lead to unpredictable and hard-to-debug issues).

There's no reason to not implement these methods. Most IDEs provides a generator for equals/hashCode. You just need to inform the IDE about your business key.

jpkroehling
  • 13,881
  • 1
  • 37
  • 39
  • Hello ! Thanks for the insight. I understand that IDE can help generating it, and there is jakarta common lang EqualsBuilder or HashCodeBuilder for that. But i were just thinking whether it's a bad idea to skip it if im satisfied with the default Object.equals() and Object.hashCode(), using the == for equality. Because once i decide to implement eq/hC, that adds a bit of cost of implementation and future maintenance. Your arguments make sense, but what about the business key fields that can be changed ? I think although most business key fields wont change, but perhaps some can change ? – Bertie Mar 04 '11 at 10:37
  • Business keys *can* change, and that's fine. That's why you are using a surrogate key :-) But usually, if the business key change to add a new property to the key, it means that your application will be redeployed. Thus, there's no problem there, as all existing objects will leave the JVM and will be loaded with the new property. And if a specific object has its own business key changed, it means it's not equal anymore to other objects with the same business key. Which is quite appropriate. So, you have nothing to lose by implementing equals/hashCode. – jpkroehling Mar 04 '11 at 10:55
  • Sorry for not being clear with my latest response. I was thinking about modifying an already existing record in db. Because according to the article, using the id in eq/hC is not enough in some cases for hibernate, so the eq/hC based on business key fields is introduced. So, i was thinking, if the business key values can be changed, how can i find the old entity inside a collection that still have the old business key values and then replace it with the new values ? This seems that i have to use the id instead to be able to locate the old entity and change the business key values. – Bertie Mar 05 '11 at 05:08
  • 1
    equals/hashCode discussions are always funny, specially when we have time :-) But in short: your business key is not supposed to change. It's acceptable (that's why you use a surrogate key), but in general, it shouldn't. So, if a business key changes for an object, it immediately becomes different than the previous instances with the same business key. Seriously, there are plenty of materials about equals/hashCode, including in "Effective Java" and "Java Persistence with Hibernate". – jpkroehling Mar 08 '11 at 07:05
3

You got the exact opposite conclusion from that article of what it was trying to convey.

Hibernate heavily relies on equals being implemented properly. It will malfunction if you don't.

In fact, almost everything does; including standard java collections.

The default implementation does not work when using persistence. You should always implement both equals and hashcode. There's a simple rule on how to do it, too:

  • For entities, use the key of the object.
  • For value objects, use the values

Always make sure the values you use in your equals/hashcode are immutable. If you pass these out (like in a getter), preferably pass them out in an immutable form.

This advice will improve your life :)

Joeri Hendrickx
  • 16,947
  • 4
  • 41
  • 53
  • Im currently using surrogate key for my id, which means, i should use only the Long id of mine in my eq/hC. Please correct me if im wrong, but this approach not ok in hibernate according to the article i posted above, because session.saveOrUpdate doesnt automatically populate the generated id field, but it has to wait until it gets flushed or commited, which can cause trouble when adding to a set. But in the other hand, this works fine with JPA, as i've tested, since calling entityManager.persist automatically populate the generated id field without having to wait for the flush and commit ? – Bertie Mar 05 '11 at 05:01
  • In my experience, this is one of the shortcomings of the way hibernate works. That's why I prefer using a business key as the primary key; it's usually available from the start. Otherwise, force hibernate to give you a key from the start (by persisting the item before you add it to a set) or do it by hand. – Joeri Hendrickx Mar 07 '11 at 09:45
3

Read this very nice article on the subject: Don't Let Hibernate Steal Your Identity.

The conclusion of the article goes like this:

Object identity is deceptively hard to implement correctly when objects are persisted to a database. However, the problems stem entirely from allowing objects to exist without an id before they are saved. We can solve these problems by taking the responsibility of assigning object IDs away from object-relational mapping frameworks such as Hibernate. Instead, object IDs can be assigned as soon as the object is instantiated. This makes object identity simple and error-free, and reduces the amount of code needed in the domain model.

Stijn Geukens
  • 15,454
  • 8
  • 66
  • 101
  • Old, but very nice article ! It explains not only why we need to override, but also provides different approaches to implement them. I think i'm gonna stick with the UUID generation approach. – Bertie Mar 08 '11 at 06:22
  • That's what I did for the project I just started; I like the approach, feels much cleaner. – Stijn Geukens Mar 08 '11 at 07:55