I am developing an application in Hibernate where I have model classes like these:
public class Employee
{
private int ID;
private String name;
private Department department;
//other properties
//constructors, getters and setters
}
Note that the ID
is not a value populated by the user and is populated using GenerationType.Identity
as the strategy
.
Also I have another class Department
as follows:
public class Department
{
private int ID;
private String name;
private Set<Employee> employees; //this is actually a HashSet
//other implementations
}
There is a ManyToOne
bi-directional relationship between an Employee
and a Department
.
So to add a new Employee
to an existing Department
, I do the following
Department existingDepartment = ...;
Employee newEmployee = ...;
existingDepartment.addEmployee(newEmployee);
employee.setDepartent(existinDepartment);
session.save(newEmployee);
Now conceptually two Employee
objects are the same if they have the same ID
. So my equals()
method in the Employee
class looks like this:
public boolean equals(Object o)
{
if(!(o instanceOf Employee))
{
return false;
}
Employee other = (Employee)o;
if(this.ID == o.etID())
{
return true;
}
return false;
}
Now the problem is when I create a new Employee();
I do not have its ID
, since it will be assigned when it will be persisted. So when I say
existingDepartment.addEmployee(newEmployee);
the internal HashSet
of the Department
object is effectively using an equals()
method which is broken [since it uses a member variable to determine equality that as not been initialized properly].
This seems like a very basic problem but, how do I solve it? Or am I designing my classes totally wrong? Or should my equals
method be re-written to compare other values instead of ID
, which I guess would be absurd.
This seems like a very basic problem but, how do I solve it? Or am I designing my classes totally wrong? Or should my equals method be re-written to compare other values instead of ID, which I guess would be absurd.
There are two different philosophies concerning this.
a) equals() / hashCode() based on DB id
Drawback: you can't compare persistent and non-persistent objects
b) equals() / hashCode() based on contents
Drawback: two objects with the same id may turn out to be non-equal.
I prefer the second approach, it makes more sense from a Java point of view (although admittedly not from a DB point of view). The only thing I'd want to make sure is that you never mix the approaches.
This has been discussed many times before, btw:
- Should I write equals() methods in JPA entities?
- What is the best practice when implementing equals() for entities with generated ids
- JPA : not overriding equals() and hashCode() in the entities?
(etc.)
Rewrite your equals method, so that it returns false, when o
is null:
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Employee other = (Employee) obj;
if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
return false;
}
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