The problem described in details in http://www.hibernate.org/109.html
The problem is that if we implement equals()/hashCode() as comparison and hashCode() of entity’s ids (see http://djeang.blogspot.com/2005/08/override-equals-and-hashcode-methods.html) then the hashCode() (and, possibly, equals()) will change after saving entities if ids are generated by DB.
To solve this issue I can suggest to use inner classes with equals()/hashCode(). It will not affect Hibernate’s internal collections taskflow, but will allow you to use ids in equals()/hashCode() after entities are persisted. On other hand hashCode() and equals() will not change in your persistent objects after you have saved it.
public class Test3 {
static class SomeEntity {
private Integer id;
private String data;
public SomeEntity() {
super();
}
public SomeEntity(Integer id, String data) {
super();
this.id = id;
this.data = data;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public class SomeEntityId {
private SomeEntity link = null;
public SomeEntityId(SomeEntity link) {
super();
this.link = link;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if ((obj == null) || (obj.getClass() != this.getClass()))
return false;
if (this.link.getClass() != ((SomeEntityId) obj).getLink().getClass())
return false;
Integer thisId = link.getId();
Integer otherId = ((SomeEntityId) obj).getLink().getId();
if ((thisId == null) || (otherId == null))
throw new RuntimeException("Id not defined!");
return thisId.equals(otherId);
}
@Override
public int hashCode() {
Integer thisId = link.getId();
if (thisId == null)
throw new RuntimeException("Id not defined!");
return thisId.hashCode();
}
public SomeEntity getLink() {
return link;
}
};
public SomeEntityId getDTO() {
return new SomeEntityId(this);
}
}
public static void main(String[] args) {
SomeEntity e0 = new SomeEntity(null, "no id");
SomeEntity e1 = new SomeEntity(1, "e1");
SomeEntity e2 = new SomeEntity(2, "e2");
SomeEntity e3 = new SomeEntity(3, "e3");
SomeEntity e33 = new SomeEntity(3, "e33");
Set aSet = new HashSet ();
// aSet.add(e0.getDTO());
aSet.add(e1.getDTO());
aSet.add(e2.getDTO());
aSet.add(e3.getDTO());
aSet.add(e33.getDTO());
System.out.println("set size: " + aSet.size());
System.out.println("set:");
for (SomeEntity.SomeEntityId seId : aSet) {
SomeEntity se = seId.getLink();
System.out.println("entity: " + se.getData());
}
}
}
I even could suggest you to add it to entities code generation in such tools as Hibernate Tools.
I would also like to mention also that SomeEntityId object could be stored in transient field of an entity.
Comments are welcome.


