Hibernate Books

All times are UTC - 5 hours [ DST ]

Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Using Primary Keys in equals() and hashCode() methods
PostPosted: Fri Jun 01, 2012 5:30 pm 

Joined: Tue Apr 10, 2012 2:57 pm
Posts: 8

After reading about Hibernate's documentation and a popular http://stackoverflow.com/questions/27581/overriding-equals-and-hashcode-in-java in StackOverflow, I understand that:

1) PK should never be used in hashCode() because it changes once it is persisted. Using PK in hashcode will also make it have different
state after persistence than before.

2) It is okay to use PK in equals() method as it can be used to compare the uniqueness of two objects.

I have a project where my java class has overriden version of equals() and hashCode() generated by Spring(Eclipse). When using the generator wizard for equals(), I chose not to include Id(PK) for comparison. My Id is an auto-generated value (@Generated). I completely understand that hibernate assigns Id value once the object is persisted i.e. if I now use my overridden equals(), I can compare to objects to be the same. To test:

1) I added multiple clone objects with all the field values same. One of the field is of Date class and I used same value "01-01-2012 11:00 PM" for all the dates. I say clone because except the Id, everything else is the same. I added 10 clone items.

2) When I perform a query saying that I need all created items that are created on or before "01-01-2012 11:00 PM", I surely expected all of them to be returned to me. and to make sure that I am not having any duplicates, I was storing the query results in HashSet object. What I got from the query results is ONLY one object which was created LASTLY i.e the Id was 10. Why is that?
Could someone please explain what's actually going on? ALSO, does it mean that if I retrieve an object edit it and then persist it back again, it won't be updated but stored as a new object?

 Post subject: Re: Using Primary Keys in equals() and hashCode() methods
PostPosted: Sun Jun 03, 2012 1:40 pm 

Joined: Tue Jun 01, 2010 4:18 am
Posts: 11
IMO, this is because you put your result on HashSet. Try this:


public class HashSetExample {

   class Person {
      public int id; public String name; public String address;
      public Person(int id, String name, String addr) {
         this.id = id; this.name = name; this.address = address;
      public int hashCode() {
         final int prime = 31;
         int result = 1;
         result = prime * result + getOuterType().hashCode();
         result = prime * result + ((name == null) ? 0 : name.hashCode());
         return result;
      public boolean equals(Object obj) {
         if (this == obj) return true;
         if (obj == null) return false;
         if (getClass() != obj.getClass()) return false;
         Person other = (Person) obj;
         if (!getOuterType().equals(other.getOuterType()))
            return false;
         if (name == null) {
            if (other.name != null) return false;
         } else if (!name.equals(other.name)) return false;
         return true;
      private HashSetExample getOuterType() { return HashSetExample.this; }
   public void hashSetExample() {
      Set<Person> personSet = new HashSet<Person>();
      personSet.add(new Person(1, "me", "address 1"));
      personSet.add(new Person(2, "me", "address 2"));
      personSet.add(new Person(3, "me", "address 3"));
      personSet.add(new Person(4, "me", "address 4"));
      Assert.assertEquals(1, personSet.size());
      List<Person> personList = new ArrayList<Person>();
      personList.add(new Person(1, "me", "address 1"));
      personList.add(new Person(2, "me", "address 2"));
      personList.add(new Person(3, "me", "address 3"));
      personList.add(new Person(4, "me", "address 4"));
      Assert.assertEquals(4, personList.size());
      Set<Person> personListToSet = new HashSet<Person>();
      Assert.assertEquals(1, personListToSet.size());

 Post subject: Re: Using Primary Keys in equals() and hashCode() methods
PostPosted: Mon Jun 04, 2012 7:29 am 

Joined: Tue Apr 10, 2012 2:57 pm
Posts: 8
Hi...Thanks for your solution.....what I did instead (before you even posted your reply)...

Map<Id, myObject> mapped = new HashMap<Id, myObject>();

This resolves my first problem which was getting the query results right. The reason is that HashMap is called by HashSet in the source code and they use:

1) equals() to check if they both are equal. This means if I ignore the Id of my object in the overridden equals(), I can say that two clone objects are equal.
2) Once it sees that two objects are not equal and therefore, can be added to the HashSet, it generates the a custom hashCode based on my Id's hashCode (NOT object's hashCode) and registers it to a hash-table using HashMap. Hence the requirement for not using Id in the overridden hashCode() mentioned in Hibernate.

To make more sense out of what I am talking about, check this out:

I always find source codes to be the ultimate proof for what's under the bonnet.

Because I am off for a couple of days, I won't be able to check what goes on. But do you think that not having Id in my equals() will make a mess when I use Hibernate for updating my persisted object. My understanding is that I need to detach the object from the persistence storage, modify it, and then call merge to save it.

What is your experience my friend :-) ?

Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.