Monday, November 22, 2010

Avoiding duplicated data using Hibernate

When using Hibernate, it happens that we have to map into the database some DTO beans linked one another by some relations. Let's see an example to explain better the situation:

public class Entity {
private int e_id;
private String type;
private String name;
private String address;
private boolean deleted;

// getters and setters
}

public class Researcher{
private int res_id;
private String fname;
private String lname;
private String email;
private int age;
private Entity entity;
private boolean deleted;

//getters and setters
}

In this case, we have a many-to-one relation between Researcher and Entity.
When we save a new Researcher, we want that Hibernate recognizes whether the related Entity is already stored into the database and avoid its duplication. So, we ask Hibernate to create a relation between the Researcher and the Entity already stored instead saving a new copy of it.
Hibernate always check whether the objects that are related to the one he is saving are already stored and uses the equals method to compare the incoming data to the ones into the database. So, why it doesn't work?
The problem is that the equals method invoked is the one for the class Object that compares the pointers to the objects (that are obviously different).
In order to make Hibernate able to recognize whether two beans are equals, we need to define the appropriate equals and hashCode methods for our beans.
Let's see these methods for Entity:
@Override
public int hashCode() {
final int prime = 23;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + (deleted ? 1231 : 1237);
result = prime * result + e_id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}



@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entity other = (Entity) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (deleted != other.deleted)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}

As can be seen, in the equals method we don't check whether the e_id is the same since when we save a Researcher we don't know the id of the Entity (we don't even know whether it already exists).

And now someone could ask how much time he has to spend in doing such boring methods. The answer is just few seconds.
If you are working with Eclipse, you can easily generate these pieces of code just in few clicks:
  • open the bean in which you want to add these methods and position the cursor in the place where you want to add the code;
  • into the menu select Source->Generate hashCode() and equals()...;
  • selects the fields that you want to be checked to find the equality (all fields are selected as default);
  • check whether the methods generated are ok.

No comments:

Post a Comment