-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: contains() and equals() in Hibernate Sets
PostPosted: Tue Jul 11, 2006 10:08 am 
Newbie

Joined: Tue Jul 11, 2006 9:57 am
Posts: 4
Hello all -

I have a one-to-many association between roles and users. I have created/tested the ORM mappings using Hibernate and successfully persisted instances of both classes. Below are simplified definitions of the classes:


Code:
/**
* A role defines a unique set of users.
*/
public class Role{
private int id;
private String name;
private Set users;
     
public void setId(int id){...}
public int getId(){...}
public void setName(String n){...}
public String getName(){...}
public void setUsers(Set users){...}
public Set getUsers(){...}

public boolean equals(Object other) {
   if(this == other) return true;
   if(!(other instanceof Role) ) return false;

   final Role a = (Role)other;
   if(a.getId() != getId()) return false;
   if(!a.getName().equals(getName())) return false;
   return true;
}
     
public int hashCode(){
   int hash = 3;
   return hash * getName().hashCode();
}

}
     
/**
* User overrides the equals() and hashCode() method
* using business propertie - should be used when invoking contains().
*/
public class User{
private String id;
     
public void setId(String id){...}
public String getId(){...}
     
public boolean equals(Object other) {
    if(this == other) return true;
    if(!(other instanceof User) ) return false;
     
    final User a = (User)other;
    if(!a.getEid().equals(getEid())) return false;
    return true;
}
     
public int hashCode(){
    int hash = 6;
    return hash * name.hashCode();
}
     
}



When I create a junit test and attempt to invoke contains() on the user collection the assertion returns true as expected. Below I have a snippet of code to illustrate:

Code:
/**
* JUnit Test that is successful.
*/
public void testRoleContains(){
  Role sysadmin = new Role("sysadmin");
  User smith = new User("jsmith123","John","Smith");
  sysadmin.addUser(smith);
  assertTrue(sysadmin.getUsers().contains(smith)); // returns true.
}




However, when I run another unit test that persists both the user and the role using Hibernate, the assertion fails.

Code:
/**
* JUnit Test. The first assertion passed the 2nd assertion fails.
*/
public void testRoleContainsPersist(){
Transaction tx = HibernateSessionFactory.currentSession().beginTransaction();

Role sysadmin = new Role("sysadmin");
User smith = new User("jsmith123","John","Smith");
sysadmin.addUser(smith);

assertTrue(sysadmin.contains(smith)); // returns true

rdao.makePersistent(sysadmin);
tx.commit();

assertTrue(sysadmin.contains(alcazar)); // returns false
}


Hibernate stresses the importance of overriding the equals() and hashCode() methods using business equality (which is what I've done). However, after I persist these objects, I cannot invoke contains() successfully. I suspect it is my implementation of equals() and/or hashCode(), however, I do not know why. I'm quite frustrated trying to find a solution to this and was hoping you can point me in the right direction. Any feedback is appreciated.

Thanks!
R. Alcazar


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 10:42 am 
Newbie

Joined: Thu Jul 06, 2006 1:01 pm
Posts: 4
Code:
assertTrue(sysadmin.contains(alcazar)); // returns false


I believe "alcazar" here is a typo. You meant "smith", right? Anyway, its strange that the assert returns a false here. The correct sequence of this test should have been:

1. Create Role
2. Create User
3. Assign User to Role
4. Persist Role (User should get persisted along with it)
5. Get id from Role
6. Load Role using id
7. Check for presence of User in Role

Are you sure you are following these steps? From the code snippet that you have posted, the assert will return true. It's a pure contains() call to the Set in Role and has nothing to do with persistence.

You can pergaps check you xml for the Set mapping and presence of inverse=true (if you have used it).


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 12:02 pm 
Newbie

Joined: Tue Jul 11, 2006 9:57 am
Posts: 4
Hello -

Thanks for the reply, you are correct "alcazar" is a typo.

I have reviewed your sequence and I agree. However, if I persist the Role as mentioned in step #4, why would I need to reload the Role in step #6. Should I not be able to invoke operations on the Role as a persistent object?

Well, I've noted some odd behavior concerning the contains() method. You are correct, this *should* be a pure comparison with equals() & hashCode(). However, the boolean result appears to be different if I invoke makePersistent() or place it outside of the transaction. This does not seem consistent to me. Are you aware of anything that may have an effect on this.

I appreciate your help with this.
Kind Regards,
R. Alcazar


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 3:39 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
you are using id in your equals/hashcode impl ...don't do that if you need to have elements in a Set while it is being persisted.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 4:08 pm 
Newbie

Joined: Tue Jul 11, 2006 9:57 am
Posts: 4
Max -

Why wouldn't I use the ID for persisted objects? As I understand it, this may be the same for objects that have not yet been assigned an ID (maybe the ID represents the initialized value). If this is the case, comparing business attributes should work.

Please advise,
R. Alcazar


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 4:30 pm 
Newbie

Joined: Tue Jul 11, 2006 9:57 am
Posts: 4
Max -

Thanks for pointing me in the right direction. I have found some documentation on using IDs within Sets and the potential to break the uniqueness of instances if they are modified.

Thanks again!
R. Alcazar


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 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.