I know that this topic has been discussed umpteen number of times, but still need some clarifications on the issue we are facing. Hibernate best practices talk about using natural keys for the equals / hashCode methods. We do have a composite key which consists of 2 parameters (say String name, Organization org) to which a particular object belongs. Unfortunately I can't use org since it is lazily loaded and leads to other issues and I don't want to create a surrogate key either (maybe auto generated from the database or a UUID created via an API call prior to object creation). What kind of options do I really have since in the above Object (name, org) fields are unique and I can't just write my logic just based on the name field itself. Is surrogate key the only option, does this mean I have to store this value as part of each row in the table?
What is the object called has a name and Organization? I'll assume it's called Foo. I take it you can't say foo.getOrganization() because the database connection is closed? Can you change your FooDAO so it loads the Organization as soon as foo is read from the database?
Then it will be available later when you need to do something with equals() and hashCode().
Hibernate best practices talk about using natural keys for the equals / hashCode methods.
Yes so I won't elaborate on this.
We do have a composite key which consists of 2 parameters (say String name, Organization org) to which a particular object belongs. Unfortunately I can't use org since it is lazily loaded and leads to other issues.
Could you elaborate a bit and maybe illustrate with some code? I'd like to understand how you got this working exactly and what the problem is.
What kind of options do I really have since in the above Object (name, org) fields are unique and I can't just write my logic just based on the name field itself.
As I said, providing more details might help. But just in case, note that calling org.getId()
on a proxy should not trigger the loading of the entity, as long as you're using property access type, so you should be able to use this in your equals implementation.
If you desire something like
public class MyEntity {
private String name;
private Organization organization;
// getter's and setter's
public boolean equals(Object o) {
if(!(o instanceof MyEntity))
return false;
MyEntity other = (MyEntity) o;
return new EqualsBuilder().append(getName(), other.getName())
.append(getOrganization(), other.getOrganization())
.isEquals();
}
}
But if you want to avoid it because you do now want to load a lazy loaded entity, you can rely on Hibernate.isInitialized method and supply your custom routine
public boolean equals(Object o) {
if(!(o instanceof MyEntity))
return false;
MyEntity other = (MyEntity) o;
boolean equals = new EqualsBuilder().append(getName(), other.getName())
.isEquals();
if(Hibernate.isInitialized(getOrganization())) {
// loaded Organization
} else {
// supply custom routine
}
return equals;
}
I have a not-updated web page where Hibernate supply the following matrix
no eq/hC at all eq/hC with the id property eq/hC with buisness key
use in a composite-id No Yes Yes
multiple new instances in set Yes No Yes
equal to same object from other session No Yes Yes
collections intact after saving Yes No Yes
Where the various problems are as follows:
use in a composite-id:
To use an object as a composite-id, it has to implement equals/hashCode in some way, == identity will not be enough in this case.
multiple new instances in set:
Will the following work or not:
HashSet someSet = new HashSet();
someSet.add(new PersistentClass());
someSet.add(new PersistentClass());
assert(someSet.size() == 2);
equal to same object from another session:
Will the following work or not:
PersistentClass p1 = sessionOne.load(PersistentClass.class, new Integer(1));
PersistentClass p2 = sessionTwo.load(PersistentClass.class, new Integer(1));
assert(p1.equals(p2));
collections intact after saving:
Will the following work or not:
HashSet set = new HashSet();
User u = new User();
set.add(u);
session.save(u);
assert(set.contains(u));
It also highlight this Thread where equals/hashCode implementation is heavily discussed