I have one BaseEntity which abstracts id and version property. this class also implements hashcode and equals based on PK (id) property.
BaseEntity{
Long id;
Long version;
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BaseEntity other = (BaseEntity) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
now two Entity A and B extends BaseEntity as below
A extends BaseEntity{
`B b`
B getB(){return b;)
void setB(B b){this.b=b;}
}
B extends BaseEntity{
}
object b1;
object a1;
a1.set(b1);
session.save(a1) //cascade save;
close session load a with lazy b and try a1.getB().equals(b1) gives false but if i compare with a1.getB().getId().equals(b1.getId()) then gives true strange!! i think it is because of java assist proxy object, anyway to resolve this?
I use
Hibernate.getClass
for many years and I never noticed a problem:To be able to lazy-load the
a.b
association, Hibernate sets theb
field ina
to a proxy. The proxy is an instance of a class that extends B, but is not B. So, your equals() method will always fail when comparing a non-proxy B instance to a proxy B instance, because it compares the classes of both objects:In the case of Hibernate entities, you should replace this with
Also, note that
equals()
andhashCode()
by using the ID, but rather by using a natural identifier. Implementing it with IDs can cause problems because entities don't have an ID until they're saved and the ID is generateda.b
before loading it. Soa.b
will be initialized to a proxy which is a subclass of B, but is not a subclass of B1 or B2. So thehashCode()
andequals()
methods should be implemented in B, but not be overridden in B1 and B2. Two B instances should be considered equal if they're instances of B, and have the same identifier.This is mostly an effect of standard Java inheritance.
a1.getB().equals(b1)
usesObject.equals()
(except if you've overridden equals() in your class), which only returns true if a1.getB() and b1 are the same instance. I don't know what you've done exactly (your code formatting is broken), but it looks like you've loadeda
again in a different session, so you get a new instance fora
anda.getB()
, and consequentlyObject.equals()
returns false.a1.getB().getId().equals(b1.getId())
usesLong.equals()
, which returns true if the long values are the same (even for different instances of the Long object), and these values are obviously the same.You can also make it works this way, usefull if you don't know wich instance is B (may happen if your
equals
is in a superclass)