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?
In other words, Hibernate uses equals and hashCode for identity, not to see if an object has been modified. It uses attribute by attribute comparisons for that.
Hibernate uses a proxy object to implement lazy loading. When we request to load the Object from the database, and the fetched Object has a reference to another concrete object, Hibernate returns a proxy instead of the concrete associated object.
How hibernate uses proxy pattern: Hibernate uses proxy pattern to lazy load entities. For lazy loaded entity or collection, hibernate defers database hit till any property other than identifier (Property marked with @Id) is accessed. The proxy object which hibernate creates has only identifier value set.
To be able to lazy-load the a.b
association, Hibernate sets the b
field in a
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:
if (getClass() != obj.getClass())
return false;
In the case of Hibernate entities, you should replace this with
if (!(obj instanceof B)) {
return false;
}
Also, note that
equals()
and hashCode()
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. So a.b
will be initialized to a proxy which is a subclass of B, but is not a subclass of B1 or B2. So the hashCode()
and equals()
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.I use Hibernate.getClass
for many years and I never noticed a problem:
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (Hibernate.getClass(this) != Hibernate.getClass(obj)) {
return false;
}
... check for values
return true;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With